package cn.mysdp.biz.facade;

import cn.mysdp.biz.domain.*;
import cn.mysdp.biz.dto.request.BaseNameRequest;
import cn.mysdp.biz.dto.request.SdpProjectForExecuteRequest;
import cn.mysdp.biz.dto.request.SdpWorkspaceAddRequest;
import cn.mysdp.biz.dto.request.SdpWorkspaceUpdateRequest;
import cn.mysdp.biz.dto.response.SdpProjectForExecuteResponse;
import cn.mysdp.biz.dto.response.SdpProjectQueryResponse;
import cn.mysdp.biz.dto.response.SdpTemplateQueryResponse;
import cn.mysdp.biz.dto.response.SdpWorkspaceQueryResponse;
import cn.mysdp.biz.repository.*;
import cn.mysdp.utils.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.mysql.cj.MysqlType;
import com.mysql.cj.protocol.Resultset;
import lombok.Getter;
import lombok.Setter;
import org.apache.calcite.avatica.util.Quoting;
import org.apache.calcite.sql.*;
import org.apache.calcite.sql.validate.SqlConformance;
import org.apache.ibatis.annotations.Results;
import org.apache.tomcat.util.codec.binary.Base64;
import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaReservedWords;
import org.mybatis.generator.codegen.mybatis3.IntrospectedTableMyBatis3Impl;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.config.PropertyRegistry;
import org.mybatis.generator.config.TableConfiguration;
import org.mybatis.generator.internal.JDBCConnectionFactory;
import org.mybatis.generator.internal.ObjectFactory;
import org.mybatis.generator.internal.db.SqlReservedWords;
import org.mybatis.generator.internal.util.JavaBeansUtil;
import org.mybatis.generator.internal.util.StringUtility;
import org.postgresql.core.Parser;
import org.postgresql.fastpath.Fastpath;
import org.postgresql.jdbc.FieldMetadata;
import org.postgresql.jdbc.PgConnection;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.sql.DataSource;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.security.Key;
import java.sql.*;
import java.util.*;
import java.util.Date;
import java.util.regex.Pattern;

import static org.mybatis.generator.internal.util.StringUtility.escapeStringForJava;

import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.SqlParser.Config;

/**
 * @ClassName:
 * @Description: FacadeImpl
 * @Author: SDP
 * @Date: 2021-10-30
 * @Version: 1.0
 * Table:
 * Comment:
 *
 */
@Service
public class ProcessSQLFacadeImpl extends BaseFacadeImpl implements ProcessSQLFacade {

    @Autowired
    DataSource dataSource;

    @Autowired
    SdpProjectMapper sdpProjectMapper;

    @Autowired
    SdpWorkspaceConfigMapper sdpWorkspaceConfigMapper;

    @Autowired
    SdpTemplateMapper sdpTemplateMapper;

    @Autowired
    SdpWorkspaceMapper sdpWorkspaceMapper;

    @Autowired
    SdpSqlMapper sdpSqlMapper;

    @Value("${spring.datasource.url}")
    private String springDatasourceUrl;

    @Value("${spring.datasource.username}")
    private String springDatasourceUsername;

    @Value("${spring.datasource.password}")
    private String springDatasourcePassword;

    @Override
    public String decryptDbPassword(SdpWorkspaceQueryResponse record) throws Exception {
        return ConnectUtil.decryptDbPassword(record);
    }

    @Override
    public boolean isToken(String token, String v) {
        return processUtil.isToken(token, v);
    }

    @Override
    public boolean isBlockToken(String token, String v) {
        return processUtil.isBlockToken(token, v);
    }

    @Override
    public String getName(String token, String name, JSONObject properties, IntrospectedColumn column, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate) throws Exception {
        return processUtil.getName(token, name, properties, column, introspectedTable, dynTemplate);
    }

    @Override
    public DynProcessTokenResult processTokenProperties(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, List<IntrospectedColumn> columns, Integer columnIndex, String token, JSONObject properties) throws Exception {
        return processUtil.processTokenProperties(introspectedTable, dynTemplate, fileName,sqlMethodName,columns,columnIndex, token, properties);
    }

    @Override
    public void processLine(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, ByteWithPos bodyBytes, ByteWithPos destBytes, List<IntrospectedColumn> columns, int columnIndex, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {
        processUtil.processLine(dataSource, introspectedTable, dynTemplate,fileName,sqlMethodName,bodyBytes,destBytes,columns,columnIndex,_processInstance,_processBodyToken,_processToken);
    }

    @Override
    public String encryptDBPassword(SdpWorkspaceUpdateRequest request) throws Exception {
        if (StringUtils.isEmpty(request.getDbPassword())
                && StringUtils.isEmpty(request.getDbUsername())
        ) {
            if ("".equals(request.getDbPassword())) {
                return "";
            }
            return null;
        }

        SdpWorkspaceWithBLOBs sdpWorkspace = sdpWorkspaceMapper.selectByPrimaryKeyWithBLOBs(request.getId());
        SdpWorkspaceQueryResponse record = new SdpWorkspaceQueryResponse();
        BeanUtils.copyProperties(sdpWorkspace, record);

        String dbPassword = request.getDbPassword();

        if (StringUtils.isEmpty(dbPassword)) {
            dbPassword = decryptDbPassword(record);
        } else {
            dbPassword = dbPassword.trim();
        }

        String dbUsername = request.getDbUsername();
        if (StringUtils.isEmpty(dbUsername)) {
            dbUsername = record.getDbUsername();
        }

        return encryptDBPassword(dbUsername, dbPassword);
    }

    @Override
    public String encryptDBPassword(SdpWorkspaceAddRequest request) throws Exception {
        if (StringUtils.isEmpty(request.getDbPassword())) {
            return "";
        }
        if (StringUtils.isEmpty(request.getDbUsername())) {
            throw new Exception("缺少db_username");
        }

        String dbPassword = request.getDbPassword();
        String dbUsername = request.getDbUsername();

        return encryptDBPassword(dbUsername, dbPassword);
    }

    public String encryptDBPassword(String dbUsername, String dbPassword) throws Exception {
        return ConnectUtil.encryptDBPassword(dbUsername, dbPassword);
    }

    public Connection getConnection(SdpWorkspaceQueryResponse workspace) throws Exception {
        SdpWorkspaceWithBLOBs record = new SdpWorkspaceWithBLOBs();
        BeanUtils.copyProperties(workspace, record);
        return getConnection(record);
    }

    public void closeConnection(String workspaceName) throws Exception {
        if (connectionMap.containsKey(workspaceName)) {
            try {
                connectionMap.get(workspaceName).close();
            }catch (Exception ex) {
                ex.printStackTrace();
            }
            connectionMap.remove(workspaceName);
        }
    }
    public void closeConnection(SdpWorkspaceQueryResponse workspace) throws Exception {
        String workspaceName = workspace.getName();
        closeConnection(workspaceName);
    }

    public void closeConnection(SdpWorkspaceWithBLOBs workspace) throws Exception {
        String workspaceName = workspace.getName();

        closeConnection(workspaceName);
    }

    public Connection getConnection(SdpWorkspaceWithBLOBs workspace) throws Exception {
        String workspaceName = workspace.getName();

        if(connectionMap.containsKey(workspaceName)) {
            return connectionMap.get(workspaceName);
        }

        Connection connection = null;

        String url = ConnectUtil.getUrl(workspace);
        JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
        jdbcConnectionConfiguration.setDriverClass(workspace.getDbClassname());
        jdbcConnectionConfiguration.setConnectionURL(url);
        jdbcConnectionConfiguration.setUserId(workspace.getDbUsername());
        String dbPassword = ConnectUtil.decryptDbPassword(workspace);
        jdbcConnectionConfiguration.setPassword(dbPassword);

        Context context = new Context(null);
        context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);
        context.addProperty(PropertyRegistry.CONTEXT_BEGINNING_DELIMITER, "`");
        context.addProperty(PropertyRegistry.CONTEXT_ENDING_DELIMITER, "`");
        context.addProperty(PropertyRegistry.CONTEXT_AUTO_DELIMIT_KEYWORDS, "true");

        contextMap.put(workspaceName, context);

        JavaTypeResolver javaTypeResolver = ObjectFactory
                .createJavaTypeResolver(context, new ArrayList<>());

        javaTypeResolverMap.put(workspaceName, javaTypeResolver);

        try {
            jdbcConnectionConfiguration.addProperty("springDatasourceUrl", springDatasourceUrl);
            jdbcConnectionConfiguration.addProperty("springDatasourceUsername", springDatasourceUsername);
            jdbcConnectionConfiguration.addProperty("springDatasourcePassword", springDatasourcePassword);

            if ("org.h2.Driver".equals(workspace.getDbClassname())
                    && !StringUtils.hasText(workspace.getDbJdbcurl())
                    && !StringUtils.hasText(workspace.getDbDatabase())) {
                connection = dataSource.getConnection();
                context.setConnection(connection);
            } else {
                ConnectionFactory connectionFactory;
                connectionFactory = new JDBCConnectionFactory(jdbcConnectionConfiguration);

                connection = connectionFactory.getConnection();
            }

            if(StringUtils.hasText(workspace.getExtraInfo())) {
                try {
                    JSONObject extraInfo = JSONObject.parseObject(workspace.getExtraInfo());
                    String searchPath = extraInfo.getString("search_path");
                    if(StringUtils.hasText(searchPath)) {
                        jdbcConnectionConfiguration.addProperty("search_path", searchPath);
                        String sql = "set search_path to "+searchPath;
                        PreparedStatement psql = connection.prepareStatement(sql);
                        psql.execute();
                    }
                }catch (Exception ex) {
                    if((ex.getMessage()+"").contains("This connection has been closed")) {
                        closeConnection(workspace);
                    }
                    System.out.println("[ERROR]无法设置search_path:"+ex.getMessage());
                    ex.printStackTrace();

                }
            }
        }catch(Exception ex) {
            ex.printStackTrace();
            if (ex instanceof SQLNonTransientConnectionException) {
                Throwable ex1 = ((SQLNonTransientConnectionException)ex).getCause();
                if (ex1 == null) {
                    throw new Exception("无法连接到数据库："+workspaceName+",数据库："+workspace.getDbHost()+":"+workspace.getDbPort()+"@"+workspace.getDbUsername()+"("+ex.getMessage()+")");
                }
                if (ex1.getMessage().indexOf("Access denied for user") >= 0) {
                    throw new Exception("数据库无权限或密码错误："+workspaceName+",数据库："+workspace.getDbHost()+":"+workspace.getDbPort()+"@"+workspace.getDbUsername()+"("+ex1.getMessage()+")"+","+ex.getMessage());
                }

                throw new Exception("无法连接到数据库："+workspaceName+",数据库："+workspace.getDbHost()+":"+workspace.getDbPort()+"@"+workspace.getDbUsername()+"("+ex1.getMessage()+")"+","+ex.getMessage());

            }
            throw new Exception("无法连接到数据库："+workspaceName+",数据库："+workspace.getDbHost()+":"+workspace.getDbPort()+"@"+workspace.getDbUsername()+":"+workspace.getDbPassword()+"("+ex.getMessage()+")");
        }
        connectionMap.put(workspaceName, connection);
        return connection;
    }

    private static Set<String> gTypSet = new HashSet<>();
    public static Integer fixPostgresqlType(Object field, Map<String, Field> fieldMap,
                                            SdpWorkspaceQueryResponse workspace,
                                            Map<String, Object> fieldValueSet,
                                            Map<Integer, String>typeByOidMap) throws IllegalAccessException {
        Integer fieldMysqlTypeId = MysqlType.FIELD_TYPE_VAR_STRING;

        String typname = typeByOidMap.get(fieldValueSet.get("oid"));
        gTypSet.add(typname);
        if(StringUtils.hasText(typname)) {
            if("datetime".equals(typname)) {
                return Types.TIMESTAMP;
            } else if ("int4".equals(typname)) {
                return Types.INTEGER;
            } else if ("int8".equals(typname)) {
                return Types.BIGINT;
            } else if ("bool".equals(typname)) {
                return Types.BIT;
            } else if ("numeric".equals(typname)) {
                return Types.NUMERIC;
            } else if ("varchar".equals(typname)) {
                return Types.VARCHAR;
            } else if ("text".equals(typname)) {
                return Types.LONGVARCHAR;
            } else if ("timestamp".equals(typname)) {
                return Types.TIMESTAMP;
            } else if ("tinyint".equals(typname)) {
                return Types.SMALLINT;
            } else if ("uint4".equals(typname)) {
                return Types.INTEGER;
            } else {
                System.out.println("debugger");
            }
        }

        String sqlType = null;
        if(fieldMap.get("sqlType") != null) {
            Object v = fieldMap.get("sqlType").get(field);
            if(v != null) {
                sqlType = v.toString();
            }
        }
        String length = null;
        if(fieldMap.get("length") != null) {
            Object v = fieldMap.get("length").get(field);
            if(v != null) {
                length = v.toString();
            }
        }
        if("0".equals(sqlType)) {
            if("4".equals(length)) {
                fieldMysqlTypeId = Types.INTEGER;
            } else {
                System.out.println("debugger:sqlType:"+sqlType+",length:"+length);
            }
        } else {
            System.out.println("debugger:sqlType:"+sqlType+",length:"+length);
        }
        return fieldMysqlTypeId;
    }

    public static void checkSingleStar(String sql) throws Exception {
        String _sql = sql;
        String[] _strs = _sql.split("\n");
        _sql = "";
        for(String s:_strs) {
            _sql += s.split("-- ")[0]+"\n";
        }
        _sql = _sql.replaceAll("\n", " ").replaceAll("\r", " ").replaceAll("\t", " ");
        while(_sql.contains("  ")) {
            _sql = _sql.replaceAll("  ", " ");
        }
        _sql = _sql.toLowerCase();
        if(_sql.contains("select *")
                || _sql.contains(" * from")
        ) {
            throw new Exception("不可直接使用*，请使用select t.*类似的语法");
        }
        _sql = _sql.replaceAll(" ", "");
        if(_sql.contains(",*")) {
            throw new Exception("不可直接使用*，请使用select t.*类似的语法");
        }
    }

    private void pringNotFoundInfo(Set<String> infoSet, String msg) {
        if (!infoSet.contains(msg)) {
            infoSet.add(msg);
            System.out.println(msg);
        }
    }

    public static Map<String, Connection> connectionMap = new HashMap<>();
    public static Map<String, Context> contextMap = new HashMap<>();
    public static Map<String, JavaTypeResolver> javaTypeResolverMap = new HashMap<>();

    public static void clearConnectionMap() {
        connectionMap.clear();
        contextMap.clear();
    }

    public static String needRestart = "";

    @Override
    public SdpProjectForExecuteResponse execute(SdpProjectForExecuteRequest request, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {
        if(StringUtils.hasText(needRestart)) {
            throw new Exception("需要重启服务:"+needRestart);
        }
        FileUtil.clear();

        try {
//            String lineSeparator = System.lineSeparator();
//            lineSeparator = "\r\n";
//            Field lineSeparatorField = System.class.getDeclaredField("lineSeparator");
//            lineSeparatorField.setAccessible(true);
//            lineSeparatorField.set(System.class, lineSeparator);

        }catch (Exception ex) {
            ex.printStackTrace(System.err);
        }

        JSONObject jsonObject = JSON.parseObject(request.getName());

        Set<String> fountFoundInfoSet = new HashSet<>();

        Map<String, SdpWorkspaceQueryResponse> sdpWorkspaceMap = new HashMap<>();
        {
            SdpWorkspaceExample example = new SdpWorkspaceExample();
            if (jsonObject.containsKey("workspace_name") && !StringUtils.isEmpty(jsonObject.getString("workspace_name"))) {
                example.createCriteria().andNameEqualTo(jsonObject.getString("workspace_name"));
            }
            //这里不能调用facade的list方法，因为facade中的list已经将密码隐藏了
            List<SdpWorkspaceWithBLOBs> list = sdpWorkspaceMapper.selectByExampleWithBLOBs(example);
            for(SdpWorkspaceWithBLOBs item: list) {
                SdpWorkspaceQueryResponse newItem = new SdpWorkspaceQueryResponse();
                BeanUtils.copyProperties(item, newItem);
                sdpWorkspaceMap.put(item.getName(), newItem);
            }
        }

        boolean globalByteAsBoolean = false;
        Map<String, Map<String, String>> sdpConfigMap = new HashMap<>();
        {
            SdpWorkspaceConfigExample example = new SdpWorkspaceConfigExample();
            if (jsonObject.containsKey("workspace_name")) {
                example.createCriteria().andWorkspaceNameEqualTo(jsonObject.getString("workspace_name"));
            }
            for(SdpWorkspaceConfigWithBLOBs item: sdpWorkspaceConfigMapper.selectByExampleWithBLOBs(example)) {
                String workspaceName = item.getWorkspaceName();
                if("byte_as_boolean".equals(item.getName()) && "1".equals(item.getValue())) {
                    globalByteAsBoolean = true;
                }
                if (!sdpWorkspaceMap.containsKey(workspaceName)) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found config workspace:"+workspaceName);
                    continue;
                }
                if (!sdpConfigMap.containsKey(workspaceName)) {
                    sdpConfigMap.put(workspaceName, new HashMap<>());
                }
                sdpConfigMap.get(workspaceName).put(item.getName(), item.getValue());
            }
        }

        Map<String, Set<String>> tableMap = new HashMap<>();
        Map<String, Set<String>> aliasTableMap = new HashMap<>();
        Map<String, Map<String, String>> aliasTableNameMap = new HashMap<>();

        Map<String, SdpProjectQueryResponse> sdpProjectMap = new HashMap<>();
        {
            SdpProjectExample example = new SdpProjectExample();
            if (jsonObject.containsKey("workspace_name")) {
                example.createCriteria().andWorkspaceNameEqualTo(jsonObject.getString("workspace_name"));
            }
            for(SdpProjectWithBLOBs item: sdpProjectMapper.selectByExampleWithBLOBs(example)) {
                if(Integer.valueOf(1).equals(request.getIsAi())) {
                    if(StringUtils.hasText(item.getExtraInfo())) {
                        try {
                            JSONObject extraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(item.getExtraInfo());
                            if(!extraInfo.containsKey("ai_tables")) {
                                continue;
                            }
                            if(!StringUtils.hasText(extraInfo.getString("ai_tables"))) {
                                continue;
                            }
                            item.setTables(extraInfo.getString("ai_tables"));
                        }catch (Exception ex) {
                            System.err.println("project的extra_info格式非法:"+item.getWorkspaceName()+","+item.getName());
                            System.err.println(ex.getMessage());
                            continue;
                        }
                    }
                }
                String workspaceName = item.getWorkspaceName();
                if(StringUtils.hasText(item.getTables())) {
                    String[] tables = item.getTables().split(",");
                    String sb = "";
                    for(String t: tables) {
                        t = t.trim();
                        if(StringUtils.hasText(t)) {
                            if(t.indexOf("-") >= 0) {
                                continue;
                            }
                        }
                        if(sb.length() > 0) {
                            sb += ",";
                        }
                        sb += t;
                    }
                    item.setTables(sb);
                }
                SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);

                SdpWorkspaceQueryResponse sdpWorkspace = sdpWorkspaceMap.get(workspaceName);
                if (sdpWorkspace == null) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found project workspace:"+workspaceName);
                    continue;
                }

                if (!sdpConfigMap.containsKey(workspaceName)) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found config for project workspace:"+workspaceName);
                    continue;
                }

                SdpProjectQueryResponse newItem = new SdpProjectQueryResponse();
                BeanUtils.copyProperties(item, newItem);

                newItem.setPropertyMap(sdpConfigMap.get(workspaceName));

                sdpProjectMap.put(workspaceName+";" + item.getName(), newItem);

                if (StringUtils.isEmpty(item.getTables())) {
                    continue;
                }

                if (!tableMap.containsKey(workspaceName)) {
                    tableMap.put(workspaceName, new HashSet<>());
                    aliasTableMap.put(workspaceName, new HashSet<>());
                    aliasTableNameMap.put(workspaceName, new HashMap<>());
                }
//                Set<String> tableSet = tableMap.get(workspaceName);
//                Set<String> aliasTableSet = aliasTableMap.get(workspaceName);

                String schema = ConnectUtil.getDatabaseName(sdpWorkspace, dataSource.getConnection());

                String[] tables = item.getTables().split(",");
                for(String name: tables) {
                    name = name.trim();
                    if (StringUtils.isEmpty(name)) {
                        continue;
                    }
                    if(name.contains("-")) {
                        if("1".equals(name.split("-")[1])) {
                            continue;
                        }
                    }
                    String oriName = name;
                    String[] names = name.split(" as ");
                    if (names.length > 1) {
                        name = names[0].trim();
                        oriName = name;
                    }
                    if(name.split(":").length > 1) {
                        oriName = name.split(":")[1];
                        tableMap.get(workspaceName).add(name.split(":")[0] + "." + schema + "." + name.split(":")[1]);
                    } else {
                        tableMap.get(workspaceName).add(workspaceName + "." + schema + "." + name);
                    }
                    if (names.length > 1) {
                        name = names[1].trim();
                    }

                    aliasTableMap.get(workspaceName).add(workspaceName + "." + schema + "." + name);
                    aliasTableNameMap.get(workspaceName).put(workspaceName + "." + schema + "." + name, oriName);
                }
            }
        }


        Map<String, Map<String, List<IntrospectedColumn>>> parameterColumnsMap = new HashMap<>();
        Map<String, List<String>> parameterColumnKeysMap = new HashMap<>();

        Map<String, List<String>> tableMapForList = new HashMap<>();

        for(String workspaceName: tableMap.keySet()) {
            System.out.println("table for workspace:"+workspaceName);
            List<String> tableList = new ArrayList<>();
            tableMapForList.put(workspaceName, tableList);

            for(String name: tableMap.get(workspaceName)) {
                System.out.println("table:"+name);
                name = name.trim();
                String names[] = name.split( " as ");
                if (names.length > 1) {
                    name = names[0].trim();
                }

                tableList.add(name);
            }
        }

        Map<String, Field> pgFieldMetadataMap = new HashMap<>();
        {
            Field[] fields = org.postgresql.jdbc.FieldMetadata.class.getDeclaredFields();
            for(Field field: fields) {
                pgFieldMetadataMap.put(field.getName(), field);
                field.setAccessible(true);
            }
        }


        Map<Integer, String> tableByOidMap = new HashMap<>();

        Map<Integer, String> typeByOidMap = new HashMap<>();
        Map<String, List<JSONObject>> columnByTableNameMap = new HashMap<>();

        for(String workspaceName: sdpWorkspaceMap.keySet()) {

            SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);

            if (!tableMap.containsKey(workspaceName)) {
//                pringNotFoundInfo(fountFoundInfoSet, "not found table workspace:"+workspaceName);
                continue;
            }

            if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                String sql = "select c.relname as TABLE_NAME,n.nspname as TABLE_SCHEM, c.oid AS object_id, c.relkind, a.attname AS name, a.attnum AS column_id, t.oid AS system_type_id, t.oid AS user_type_id,\n" +
                        "a.attlen AS max_length, CAST(NULL AS INTEGER) AS precision, CAST(NULL AS INTEGER) AS scale, coll.collname AS collation_name,\n" +
                        "(CASE a.attnotnull WHEN TRUE THEN 0 ELSE 1 END) AS is_nullable, 0 AS is_ansi_padded, 0 AS is_rowguidcol, 0 AS is_identity,\n" +
                        "0 AS is_computed, 0 AS is_filestream, 0 AS is_replicated, 0 AS is_non_sql_subscribed, 0 AS is_merge_published,\n" +
                        "0 AS is_dts_replicated, 0 AS is_xml_document, 0 AS xml_collection_id, COALESCE(d.oid, CAST(0 AS oid)) AS default_object_id, \n" +
                        "COALESCE((SELECT TOP(1) pg_constraint.oid FROM pg_constraint WHERE pg_constraint.conrelid = t.oid \n" +
                        "AND pg_constraint.contype = 'c' AND array_position(pg_constraint.conkey, a.attnum) IS NOT NULL), \n" +
                        "CAST(0 AS oid)) AS rule_object_id, 0 AS is_sparse, 0 AS is_column_set, 0 AS generated_always_type,\n" +
                        "CAST('NOT_APPLICABLE' AS VARCHAR(60)) AS generated_always_type_desc, CAST(NULL AS integer) AS encryption_type,\n" +
                        "CAST(NULL AS VARCHAR(64)) AS encryption_type_desc, CAST(NULL AS TEXT) AS encryption_algorithm_name,\n" +
                        "CAST(NULL AS INTEGER) AS column_encryption_key_id, CAST(NULL AS TEXT) AS column_encryption_key_database_name, \n" +
                        "0 AS is_hidden, 0 AS is_masked \n" +
                        "FROM pg_attribute a JOIN pg_class c ON c.oid = a.attrelid \n" +
                        "left join pg_catalog.pg_namespace n on c.relnamespace = n.oid\n" +
                        "JOIN pg_type t ON t.oid = a.atttypid JOIN pg_namespace s ON s.oid = c.relnamespace \n" +
                        "LEFT JOIN pg_attrdef d ON c.oid = d.adrelid AND a.attnum = d.adnum LEFT JOIN pg_collation coll ON coll.oid = t.typcollation \n" +
                        "WHERE 88=88\n" +
                        "and c.relkind in ('r', 'v', 'm')\n" +
                        "and n.nspname not in ('information_schema', 'pg_catalog', 'sys_catalog', 'SYS_HM', 'sysaudit', 'sysmac','sys', 'anon', 'src_restrict', '')\n" +
                        "and a.attnum > 0 AND a.attisdropped = FALSE AND (c.relkind = 'r' OR c.relkind = 'v' OR c.relkind = 'm' OR c.relkind = 'f' OR c.relkind = 'p') \n" +
                        "AND has_column_privilege(CONCAT(quote_ident(s.nspname), '.', quote_ident(c.relname)), a.attname, 'SELECT,INSERT,UPDATE,REFERENCES') = TRUE \n" +
                        "AND has_schema_privilege(s.oid, 'USAGE') = true\n" +
                        "order by 1,2,3,6";

                PreparedStatement mysqlStatement;

                Connection connection = getConnection(workspace);

                try {
                    mysqlStatement = connection.prepareStatement(sql);
                }catch(Exception ex) {
                    if((ex.getMessage()+"").contains("This connection has been closed")) {
                        closeConnection(workspace);
                    }
                    ex.printStackTrace(System.err);
                    System.err.println("=== prepareStatement error, sql ===");
                    System.err.println(sql);
                    throw ex;
                }
                ResultSet rs = mysqlStatement.executeQuery();
                ResultSetMetaData rsm = rs.getMetaData();
                Set<String> fieldsSet = new HashSet<>();
                for(int i = 0; i < rsm.getColumnCount(); i++) {
                    try {
                        fieldsSet.add(rsm.getColumnName(i+1));
                    }catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }

                while(rs.next()) {

                    String TABLE_SCHEM = rs.getString("TABLE_SCHEM"); //$NON-NLS-1$
                    String TABLE_NAME = rs.getString("TABLE_NAME"); //$NON-NLS-1$
                    if(!columnByTableNameMap.containsKey(TABLE_SCHEM+"."+TABLE_NAME)) {
                        columnByTableNameMap.put(TABLE_SCHEM+"."+TABLE_NAME, new ArrayList<>());
                    }

                    JSONObject jsonObject1 = new JSONObject();

                    for(String f:fieldsSet) {
                        try {
                            Object v = rs.getObject(f);
                            if(v != null) {
                                jsonObject1.put(f, v);
                            }
                        }catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    columnByTableNameMap.get(TABLE_SCHEM+"."+TABLE_NAME).add(jsonObject1);
                }
                mysqlStatement.close();
            }

            if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                String sql = "SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM, c.relname AS TABLE_NAME, CASE n.nspname ~ '^pg_' OR n.nspname = 'information_schema' WHEN true THEN CASE  WHEN n.nspname = 'pg_catalog' OR n.nspname = 'information_schema' then CASE c.relkind   WHEN 'r' THEN 'SYSTEM TABLE'   WHEN 'v' THEN 'SYSTEM VIEW' WHEN 'i' THEN 'SYSTEM INDEX'   ELSE NULL   END  WHEN n.nspname = 'pg_toast' THEN CASE c.relkind   WHEN 'r' THEN 'SYSTEM TOAST TABLE' WHEN 'i' THEN 'SYSTEM TOAST INDEX'   ELSE NULL   END  ELSE CASE c.relkind   WHEN 'r' THEN 'TEMPORARY TABLE'   WHEN 'p' THEN 'TEMPORARY TABLE' WHEN 'i' THEN 'TEMPORARY INDEX'   WHEN 'S' THEN 'TEMPORARY SEQUENCE'   WHEN 'v' THEN 'TEMPORARY VIEW'   ELSE NULL   END  END  WHEN false then CASE c.relkind  WHEN 'r' THEN 'TABLE'  WHEN 'p' THEN 'PARTITIONED TABLE'  WHEN 'i' THEN 'INDEX'  WHEN 'P' then 'PARTITIONED INDEX'  WHEN 'S' THEN 'SEQUENCE'  WHEN 'v' THEN 'VIEW'  WHEN 'c' THEN 'TYPE'  WHEN 'f' THEN 'FOREIGN TABLE'  WHEN 'm' THEN 'MATERIALIZED VIEW'  ELSE NULL  END ELSE NULL  END  AS TABLE_TYPE,d.description AS REMARKS,  '' as TYPE_CAT, '' as TYPE_SCHEM, '' as TYPE_NAME, '' AS SELF_REFERENCING_COL_NAME, '' AS REF_GENERATION, c.oid  FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c \n" +
                        "LEFT JOIN pg_catalog.pg_description d ON (c.oid = d.objoid AND d.objsubid = 0  and d.classoid = 'pg_class'::regclass)\n" +
                        "WHERE c.relnamespace = n.oid and c.relkind in ('r', 'v', 'm') and n.nspname not in ('information_schema', 'pg_catalog', 'sys_catalog', 'SYS_HM', 'sysaudit', 'sysmac','sys', 'anon', 'src_restrict', '')\n" +
                        "ORDER BY TABLE_TYPE,TABLE_SCHEM,TABLE_NAME \n";

                PreparedStatement mysqlStatement;

                Connection connection = getConnection(workspace);

                try {
                    mysqlStatement = connection.prepareStatement(sql);
                }catch(Exception ex) {
                    if((ex.getMessage()+"").contains("This connection has been closed")) {
                        closeConnection(workspace);
                    }
                    ex.printStackTrace(System.err);
                    System.err.println("=== prepareStatement error, sql ===");
                    System.err.println(sql);
                    throw ex;
                }
                ResultSet rs = mysqlStatement.executeQuery();
                while(rs.next()) {
                    String TABLE_SCHEM = rs.getString("TABLE_SCHEM"); //$NON-NLS-1$
                    String TABLE_NAME = rs.getString("TABLE_NAME"); //$NON-NLS-1$
                    Integer oid = rs.getInt("OID");
                    tableByOidMap.put(oid, TABLE_SCHEM+"."+TABLE_NAME);
                }
                mysqlStatement.close();
            }

            if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                String sql = "SELECT * from pg_type";

                PreparedStatement mysqlStatement;

                Connection connection = getConnection(workspace);

                try {
                    mysqlStatement = connection.prepareStatement(sql);
                }catch(Exception ex) {
                    if((ex.getMessage()+"").contains("This connection has been closed")) {
                        closeConnection(workspace);
                    }
                    ex.printStackTrace(System.err);
                    System.err.println("=== prepareStatement error, sql ===");
                    System.err.println(sql);
                    throw ex;
                }
                ResultSet rs = mysqlStatement.executeQuery();
                while(rs.next()) {
                    String typname = rs.getString("typname"); //$NON-NLS-1$
                    Integer oid = rs.getInt("oid");
                    typeByOidMap.put(oid, typname);
                }
                mysqlStatement.close();
            }

            if(connectionMap.containsKey(workspaceName)) {
                continue;
            }

            SdpWorkspaceWithBLOBs workspaceWithBLOBs = sdpWorkspaceMapper.selectByIdWithBLOBs(workspace.getId());
            getConnection(workspaceWithBLOBs);
        }

        {
            SdpSqlExample example = new SdpSqlExample();
            if (jsonObject.containsKey("workspace_name")) {
                example.createCriteria().andWorkspaceNameEqualTo(jsonObject.getString("workspace_name"));
            }
            example.setOrderByClause("workspace_name, table_name, parameter_catalog_type,parameter_catalog,sort_no,name, id");
            List<SdpSqlWithBLOBs> sdpSqls = sdpSqlMapper.selectByExampleWithBLOBs(example);
            for (SdpSqlWithBLOBs item : sdpSqls) {
                String workspaceName = item.getWorkspaceName();
                SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);
                String schema = ConnectUtil.getDatabaseName(workspace, getConnection(workspace));

                if (!tableMap.containsKey(workspaceName)) {
//                pringNotFoundInfo(fountFoundInfoSet, "not found table workspace:"+workspaceName);
                    continue;
                }

                if (workspace == null) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found workspace for sql:" + workspaceName);
                    continue;
                }
                if (!sdpConfigMap.containsKey(workspaceName)) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found config workspace for sql:" + workspaceName);
                    continue;
                }

                Connection connection = getConnection(workspace);

                Context context = contextMap.get(workspaceName);
                Set<String> tableSet = tableMap.get(workspace.getName());
                Set<String> aliasTableSet = aliasTableMap.get(workspace.getName());
                Map<String, String> workspaceAliasTableNameMap = aliasTableNameMap.get(workspace.getName());
                if (tableSet == null || aliasTableSet == null || workspaceAliasTableNameMap == null) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found tableSet for workspace:" + workspaceName);
                    continue;
                }

                String aliasTableName = item.getTableName();
                String tableName = item.getTableName();

                String fullAliasTableName = workspaceName+"."+schema+"."+aliasTableName;

                if(workspaceAliasTableNameMap.containsKey(fullAliasTableName)) {
                    tableName = workspaceAliasTableNameMap.get(fullAliasTableName);
                }

                String fullTableName = workspaceName+"."+schema+"."+tableName;

                if(!tableSet.contains(fullTableName) && !aliasTableSet.contains(fullTableName) && !workspaceAliasTableNameMap.containsKey(fullAliasTableName)) {
                    pringNotFoundInfo(fountFoundInfoSet, "ignore sql for not found tableSet for workspace:" + workspaceName+","+tableName);
                    continue;
                }
                String parameterCatalogName = item.getParameterCatalog();
                String parameterCatalogType = item.getParameterCatalogType();
                String parameterJavaReturnType = item.getJavaReturnType();
                String parameterJavaTypeName = item.getJavaType().replaceAll(" ", "");
                String parameterName = item.getName();
                String parameterMode = item.getParameterMode();
                String parameterSql = item.getParameterSql();
                String parameterSqlValue = item.getParameterSqlValue();
                String parameterExtraInfo = item.getExtraInfo();

                Integer parameterSqlValueIngore = 0;
                if (Integer.valueOf(1).equals(item.getParameterSqlValueIgnore())) {
                    parameterSqlValueIngore = 1;
                }
                String parameterJavaBody = item.getJavaBody();
                Integer parameterSqlIsSimple = item.getParameterSqlIssimple();
                Integer parameterSqlReutrnNoList = item.getParameterSqlReturnNolist();
                Integer parameterNullable = item.getParameterNullable();
                Integer parameterIsLike = item.getParameterIsLike();
                Integer parameterIsImportExcel = item.getParameterIsImportExcel();
                Integer parameterIsExportExcel = item.getParameterIsExportExcel();
                Integer parameterWithoutTest = item.getParameterWithoutTest();
                JSONObject parameterExtraInfoJSONObject = new JSONObject();
                if (StringUtils.hasText(parameterExtraInfo)) {
                    try {
                        parameterExtraInfoJSONObject = JSON.parseObject(parameterExtraInfo);
                    }catch (Exception ex) {
                        System.err.println(parameterExtraInfo);
                        ex.printStackTrace(System.err);
                        throw new Exception("extra_info不是合法的json格式：" + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                    }
                }
                Integer parameterIsCollection = parameterExtraInfoJSONObject.getInteger("is_collection");
                String parameterSqlReplaceLine = parameterExtraInfoJSONObject.getString("sql_replace_line");

                if (StringUtils.isEmpty(parameterMode)) {
                    throw new Exception("!!! === parameter_mode不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }

                if (StringUtils.isEmpty(parameterCatalogName)) {
                    throw new Exception("!!! === parameter_catalog不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }

                if (StringUtils.isEmpty(parameterCatalogType)) {
                    throw new Exception("!!! === parameter_catalog_type不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }
                if (parameterName != null && Pattern.matches("_[0-9]", parameterName)) {
                    throw new Exception("!!! === parameter_name不可以在下划线后跟随数字! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }
                if (parameterCatalogName != null && Pattern.matches("_[0-9]", parameterCatalogName)) {
                    throw new Exception("!!! === parameter_catalog不可以在下划线后跟随数字! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }
                if (parameterCatalogType != null && Pattern.matches("_[0-9]", parameterCatalogType)) {
                    throw new Exception("!!! === parameter_catalog_type不可以在下划线后跟随数字! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }

                if (!parameterName.equals(JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterName), false)))) {
                    throw new Exception("name：_后必须为小写英文字母:" + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }
                if (!parameterCatalogType.equals(JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterCatalogType), false)))) {
                    throw new Exception("catalog_type非法：_后必须为小写英文字母:" + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }
                parameterMode = JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterMode), false));
                parameterCatalogName = JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterCatalogName), false));
                parameterCatalogType = JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterCatalogType), false));
                parameterName = JavaBeansUtil.getAjaxString(JavaBeansUtil.getCamelCaseString(JavaBeansUtil.getAjaxString(parameterName), false));


                if ("sql".equals(parameterCatalogName)) {
                    if (StringUtils.isEmpty(parameterSql)) {
                        throw new Exception("!!! === parameter_sql不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                    }
                } else if ("api.request".equals(parameterCatalogName) ||
                        "api.response".equals(parameterCatalogName)) {
                    if (!"remove".equals(parameterMode)) {
                        if (StringUtils.isEmpty(parameterName)) {
                            throw new Exception("!!! === parameter_name不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                        }
                        if (StringUtils.isEmpty(parameterJavaTypeName)) {
                            throw new Exception("!!! === parameter_java_type不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                        }
                    }
                } else if ("api.facade".equals(parameterCatalogName)) {
                    if (!"remove".equals(parameterMode)) {
                        if (StringUtils.isEmpty(parameterJavaTypeName)) {
                            throw new Exception("!!! === parameter_java_type不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                        }
                        if (StringUtils.isEmpty(parameterJavaReturnType)) {
                            throw new Exception("!!! === parameter_java_return_type不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                        }
                    }
                } else if ("sql.param".equals(parameterCatalogName)) {
                    if (StringUtils.isEmpty(parameterName)) {
                        throw new Exception("!!! === parameter_name不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                    }
                    if (!Integer.valueOf(1).equals(parameterSqlValueIngore) && StringUtils.isEmpty(parameterSqlValue)) {
                        throw new Exception("!!! === parameter_sql_value不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                    }
                } else if ("sql.response".equals(parameterCatalogName)) {
                    if (StringUtils.isEmpty(parameterName)) {
                        throw new Exception("!!! === parameter_name不能为空! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                    }
                } else {
                    throw new Exception("!!! === parameter_catalog类型非法! " + tableName + "," + parameterCatalogName + "." + parameterCatalogType + ", " + parameterName);
                }

                FullyQualifiedJavaType parameterType;

                if (StringUtils.isEmpty(parameterCatalogType)) {
                    parameterCatalogType = "";
                }
                if (parameterJavaTypeName.startsWith("List<")) {
                    String typeName = parameterJavaTypeName.replace("List<", "");
                    typeName = typeName.replace(">", "");
                    parameterType = FullyQualifiedJavaType.getNewListInstance();
                    parameterType.addTypeArgument(new FullyQualifiedJavaType(typeName));
                } else {
                    if ("Date".equals(parameterJavaTypeName)) {
                        parameterType = new FullyQualifiedJavaType("java.util.Date");
                    } else {
                        parameterType = new FullyQualifiedJavaType(parameterJavaTypeName);
                    }
                }

                String jdbcTypeName = "VARCHAR";
                if ("Integer".equals(parameterJavaTypeName)) {
                    jdbcTypeName = "INTEGER";
                } else if ("Long".equals(parameterJavaTypeName)) {
                    jdbcTypeName = "BIGINT";
                } else if ("Double".equals(parameterJavaTypeName)) {
                    jdbcTypeName = "DOUBLE";
                } else if ("Date".equals(parameterJavaTypeName)) {
                    jdbcTypeName = "TIMESTAMP";
                }

                IntrospectedColumn introspectedColumn = new IntrospectedColumn();
                introspectedColumn.setContext(context);
                introspectedColumn.setJdbcTypeName(jdbcTypeName);
                if ("Date".equals(parameterJavaTypeName)) {
                    introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType("java.util.Date"));
                } else {
                    introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType(parameterJavaTypeName));
                }
                introspectedColumn.setJavaProperty(JavaBeansUtil.getCamelCaseString(parameterName, false));
                introspectedColumn.setActualColumnName(parameterName);
                introspectedColumn.setRemarks(item.getRemarks());

                introspectedColumn.setParameterImports(item.getJavaImports());
                introspectedColumn.setParameterJavaReturnType(parameterJavaReturnType);
                introspectedColumn.setParameterJavaType(parameterJavaTypeName);
                introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType(parameterJavaTypeName));

                if(StringUtils.hasText(item.getProjectNames())) {
                    for(String s: item.getProjectNames().split(",")) {
                        introspectedColumn.getSqlProjectSet().add(s.trim());
                    }
                }
                introspectedColumn.setParameterRemark(item.getRemarks());
                introspectedColumn.setParameterMode(parameterMode);
                introspectedColumn.setParameterCatalog(parameterCatalogName);
                introspectedColumn.setParameterCatalogType(parameterCatalogType);
                introspectedColumn.setParameterName(parameterName);
                introspectedColumn.setParameterSql(parameterSql);
                introspectedColumn.setParameterSqlValue(parameterSqlValue);
                introspectedColumn.setParameterExtraInfo(parameterExtraInfo);
                introspectedColumn.setParameterJavaBody(parameterJavaBody);

                introspectedColumn.setParameterSqlIsSimple(parameterSqlIsSimple);
                introspectedColumn.setParameterSqlReturnNoList(parameterSqlReutrnNoList);
                introspectedColumn.setParameterNullable(parameterNullable);
                introspectedColumn.setSqlIsInterface(item.getIsInterface());
                introspectedColumn.setParameterIsLike(parameterIsLike);
                introspectedColumn.setParameterIsCollection(parameterIsCollection);
                introspectedColumn.setParameterSqlReplaceLine(parameterSqlReplaceLine);
                introspectedColumn.setParameterWithoutTest(parameterWithoutTest);
                introspectedColumn.setParameterIsImportExcel(parameterIsImportExcel);
                introspectedColumn.setParameterIsExportExcel(parameterIsExportExcel);
                introspectedColumn.setParameterIgnoreSqlValue(parameterSqlValueIngore);

                if ("api.facade".equals(introspectedColumn.getParameterCatalog())) {
                    if (StringUtils.isEmpty(introspectedColumn.getParameterName())) {
                        introspectedColumn.setParameterName("request");
                    }
                    introspectedColumn.setActualColumnName(introspectedColumn.getParameterCatalogType());
                }

                if ("sql".equals(introspectedColumn.getParameterCatalog())) {
                    introspectedColumn.setActualColumnName(introspectedColumn.getParameterCatalogType());
                }

                if (!parameterColumnsMap.containsKey(workspaceName + "." + schema + "." + tableName)) {
                    parameterColumnsMap.put(workspaceName + "." + schema + "." + tableName, new HashMap<>());
                    parameterColumnKeysMap.put(workspaceName + "." + schema + "." + tableName, new ArrayList<>());
                }
                String key;
                if ("rename".equals(parameterMode)) {
                    key = parameterCatalogName;
                } else {
                    key = parameterCatalogName + "." + parameterCatalogType;
                }
                if (!parameterColumnsMap.get(workspaceName + "." + schema + "." + tableName).containsKey(key)) {
                    parameterColumnsMap.get(workspaceName + "." + schema + "." + tableName).put(key, new ArrayList<>());
                    parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add(key);
                }
                parameterColumnsMap.get(workspaceName + "." + schema + "." + tableName).get(key).add(introspectedColumn);

                tableSet.add(workspaceName + "." + schema + "." + tableName);

                if ("sql".equals(introspectedColumn.getParameterCatalog())) {
                    PreparedStatement mysqlStatement = null;
                    try {
                        String sql = parameterSql;
                        try {
                            mysqlStatement = connection.prepareStatement(sql);
                        } catch (Exception ex) {
                            if((ex.getMessage()+"").contains("This connection has been closed")) {
                                closeConnection(workspace);
                            }
                            ex.printStackTrace(System.err);
                            System.err.println("=== prepareStatement error, sql ===");
                            System.err.println(sql);
                            throw ex;
                        }
                        ResultSetMetaData resultSetMetaData;
                        try {
                            resultSetMetaData = mysqlStatement.getMetaData();
                        } catch (Exception ex) {
                            ex.printStackTrace(System.err);
                            System.err.println("=== getMetaData error, sql ===");
                            System.err.println(sql);
                            throw new Exception(schema+"."+tableName+introspectedColumn.getParameterCatalog()+","+introspectedColumn.getParameterCatalogType()+","+introspectedColumn.getParameterName()+":"+ex.getMessage());
                        }


                        Object[] jdbcFields = ConnectUtil.getMetaFields(resultSetMetaData);
                        int oriColumnCount = jdbcFields.length;

                        Map<String, Method> methodMap = new HashMap<>();
                        methodMap.put("getName", null);
                        methodMap.put("getTableName", null);
                        methodMap.put("getOriginalTableName", null);
                        methodMap.put("getColumnName", null);
                        methodMap.put("getFullName", null);
                        methodMap.put("getOriginalColumnName", null);
                        methodMap.put("getDatabaseName", null);

                        Map<String, Field> fieldMap = new HashMap<>();

                        Class clz = null;
                        if (jdbcFields.length > 0) {
                            clz = jdbcFields[0].getClass();
                        }
                        while (clz != null) {
                            int count = 0;
                            Method[] methods = jdbcFields[0].getClass().getDeclaredMethods();
                            for (Method method : methods) {
                                count = 0;
                                for (String fieldKey : methodMap.keySet()) {
                                    if (methodMap.get(fieldKey) != null) {
                                        count++;
                                        continue;
                                    }
                                    if (fieldKey.equals(method.getName())) {
                                        method.setAccessible(true);
                                        methodMap.put(fieldKey, method);
                                        count++;
                                    }
                                }
                                if (count == methodMap.size()) {
                                    break;
                                }
                            }
                            if (count == methodMap.size()) {
                                break;
                            }
                            clz = clz.getSuperclass();
                        }

                        if (jdbcFields.length > 0) {
                            clz = jdbcFields[0].getClass();
                        }
                        while (clz != null) {
                            int count = 0;
                            Field[] fields = jdbcFields[0].getClass().getDeclaredFields();
                            for (Field field : fields) {
                                try {
                                    if(!fieldMap.containsKey(field.getName()) || fieldMap.get(field.getName()) == null) {
                                        field.setAccessible(true);
                                        fieldMap.put(field.getName(), field);
                                    }
                                }catch (Exception ex) {

                                }
                            }
                            clz = clz.getSuperclass();
                        }

                        for (Object field : jdbcFields) {
                            Map<String, String> fieldInfoMap = new HashMap<>();
                            String fieldOriginalTableName = null;
                            if(fieldMap.get("originalTableName") != null) {
                                Object v = fieldMap.get("originalTableName").get(field);
                                if(v != null) {
                                    fieldOriginalTableName = v.toString();
                                    fieldInfoMap.put("originalTableName", fieldOriginalTableName);
                                }
                            } else if(fieldMap.get("tableOid") != null) {
                                Object v = fieldMap.get("tableOid").get(field);
                                if(v != null && tableByOidMap.containsKey(v)) {
                                    String name = tableByOidMap.get(v);
                                    fieldOriginalTableName = name.split("\\.")[1];
                                    fieldInfoMap.put("originalTableName", fieldOriginalTableName);
                                }
                            }
                            if(fieldMap.get("originalColumnName") != null) {
                                Object v = fieldMap.get("originalColumnName").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("originalColumnName", v.toString());
                                }
                            } else {
                                if(fieldMap.get("metadata") != null) {
                                    Object v = fieldMap.get("metadata").get(field);
                                    if(v instanceof org.postgresql.jdbc.FieldMetadata) {
                                        org.postgresql.jdbc.FieldMetadata metadata = (FieldMetadata) v;
                                        Field f = pgFieldMetadataMap.get("columnName");
                                        if(f != null) {
                                            fieldInfoMap.put("originalColumnName", v.toString());
                                        }
                                    }
                                }
                            }
                            if(fieldMap.get("name") != null) {
                                Object v = fieldMap.get("name").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("name", v.toString());
                                }
                            }
                            if (!fieldInfoMap.containsKey("name") && fieldMap.get("columnName") != null) {
                                Object v = fieldMap.get("columnName").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("name", v.toString());
                                }
                            }
                            if (!fieldInfoMap.containsKey("name") && fieldMap.get("columnLabel") != null) {
                                Object v = fieldMap.get("columnLabel").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("name", v.toString());
                                }
                            }
                            if(fieldMap.get("tableName") != null) {
                                Object v = fieldMap.get("tableName").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("tableName", v.toString());
                                }
                            }
                            if(fieldMap.get("columnName") != null) {
                                Object v = fieldMap.get("columnName").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("columnName", v.toString());
                                }
                            } else if (fieldMap.get("columnLabel") != null) {
                                Object v = fieldMap.get("columnLabel").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("columnName", v.toString());
                                }
                            }
                            if(fieldMap.get("databaseName") != null) {
                                Object v = fieldMap.get("databaseName").get(field);
                                if(v != null) {
                                    fieldInfoMap.put("databaseName", v.toString());
                                }
                            }
                            if (!StringUtils.hasText(fieldInfoMap.get("databaseName")) && "org.postgresql.Driver".equals(workspace.getDbClassname())) {
                                fieldInfoMap.put("databaseName", "public");
                            }

                            for(String fieldName: fieldMap.keySet()) {
                                if (!StringUtils.hasText(fieldInfoMap.get(fieldName)) && fieldMap.get(fieldName) != null) {
                                    Object v = fieldMap.get(fieldName).get(field);
                                    if(v != null) {
                                        fieldInfoMap.put(fieldName, v.toString());
                                    }
                                }
                            }

                            if (!StringUtils.isEmpty(fieldOriginalTableName)) {
                                tableSet.add(workspaceName + "." + schema + "." + fieldOriginalTableName);
                            }
                            introspectedColumn.getFieldInfo().add(fieldInfoMap);
                            introspectedColumn.getFieldInfoMap().put(fieldInfoMap.get("databaseName")+"."+fieldInfoMap.get("originalTableName")+"."+fieldInfoMap.get("columnName"), fieldInfoMap);
                            introspectedColumn.getFieldInfoMap().put(fieldInfoMap.get("databaseName")+"."+fieldInfoMap.get("tableName")+"."+fieldInfoMap.get("columnName"), fieldInfoMap);
                            introspectedColumn.getFieldInfoMap().put("column."+fieldInfoMap.get("columnName"), fieldInfoMap);
                        }

                    } catch (Exception ex) {
                        ex.printStackTrace(System.err);
                        throw ex;
                    } finally {
                        if (mysqlStatement != null) {
                            mysqlStatement.close();
                        }
                    }
                }

                if(StringUtils.hasText(introspectedColumn.getParameterSql())) {
                    if("sql".equals(introspectedColumn.getParameterCatalog())) {
                        int pos = 0;
                        String lastName = null;
                        String lastBlock = null;
                        List<String> lines = new ArrayList<>();

                        while(pos < introspectedColumn.getParameterSql().length()) {
                            int nextPos = introspectedColumn.getParameterSql().indexOf("\n", pos);
                            if(nextPos < 0) {
                                nextPos = introspectedColumn.getParameterSql().length();
                            }
                            String line = introspectedColumn.getParameterSql().substring(pos, nextPos);
                            do {
                                if (line.indexOf("/*") >= 0) {
                                    line = line.substring(line.indexOf("/*")+2).trim();
                                    if(StringUtils.hasText(line)) {
                                        lastName = line;
                                        continue;
                                    }
                                }
                                if (line.indexOf("*/") >= 0){
                                    line = line.substring(0, line.indexOf("*/"));
                                    if(lastName != null) {
                                        if(StringUtils.hasText(line)) {
                                            if(lastBlock != null) {
                                                lastBlock = line;
                                            } else {
                                                lastBlock += System.lineSeparator()+line;
                                            }
                                        }
                                        if(lastBlock != null) {
                                            if(!introspectedColumn.getReplaceTableAnnotationMap().containsKey(lastName)) {
                                                introspectedColumn.getReplaceTableAnnotationMap().put(lastName, lastBlock);
                                            } else {
                                                introspectedColumn.getReplaceTableAnnotationMap().put(lastName, introspectedColumn.getReplaceTableAnnotationMap().get(lastName)+System.lineSeparator()+lastBlock);
                                            }
                                        }
                                    }
                                    lastName = null;
                                    lastBlock = null;
                                }
                                if(lastName != null) {
                                    if(lastBlock == null) {
                                        lastBlock = line;
                                    } else {
                                        lastBlock += System.lineSeparator()+line;
                                    }
                                }
                            }while(false);

                            pos=nextPos+1;
                        }
                    }
                }



            }
        }

        Map<String, IntrospectedTable> introspectedTableMap = new HashMap<>();

        for(String workspaceName: tableMap.keySet()) {
            Set<String> tableSet = tableMap.get(workspaceName);
            SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);
            Context context = contextMap.get(workspaceName);
            for(String name: tableSet) {
                TableConfiguration tc = new TableConfiguration(context);
                String[] names = name.split("\\.");
                if ("org.h2.Driver".equals(workspace.getDbClassname())) {
                    tc.setSchema("public");
                    tc.setCatalog("public");
                } else {
                    tc.setCatalog(names[1]);
                }
                tc.setTableName(names[2]);
                context.addTableConfiguration(tc);
            }

            List<String> warnings = new ArrayList<>();


            context.introspectTables(null,
                    warnings,
                    null);
            if (warnings.size() > 0) {
                for(String line: warnings) {
                    if (!line.startsWith("Warning")) {
                        throw new Exception("错误："+warnings.get(0));
                    }
                }
            }

            Field introspectedTablesField = cn.mysdp.utils.JavaBeansUtil.getField(context.getClass(), "introspectedTables");
            introspectedTablesField.setAccessible(true);
            List<IntrospectedTable> introspectedTables = (List<IntrospectedTable>) introspectedTablesField.get(context);
            for(IntrospectedTable introspectedTable: introspectedTables) {
                introspectedTableMap.put(workspaceName + "." + introspectedTable.getTableConfiguration().getCatalog() + "." + introspectedTable.getTableConfiguration().getTableName(), introspectedTable);
                for(IntrospectedColumn column: introspectedTable.getAllColumns()) {
                    if(globalByteAsBoolean && "java.lang.Byte".equals(column.getFullyQualifiedJavaType().getFullyQualifiedName())) {
                        column.setFullyQualifiedJavaType(new FullyQualifiedJavaType("java.lang.Boolean"));
                    }
                }
            }

        }

        for(String name: introspectedTableMap.keySet()) {
            System.out.println("introspected table: "+name);
        }

        try {
            //process select
            for(String fullName: parameterColumnKeysMap.keySet()) {
                String[] names = fullName.split("\\.");
                String workspaceName = names[0];

                SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);

                String schema = names[1];
                String tableName = names[2];
                Connection connection = getConnection(workspace);
                Context context = contextMap.get(workspaceName);
                JavaTypeResolver javaTypeResolver = javaTypeResolverMap.get(workspaceName);

                Map<String, List<IntrospectedColumn>> parameterColumns = parameterColumnsMap.get(workspaceName + "." + schema + "." + tableName);

                if (!parameterColumnKeysMap.containsKey(workspaceName + "." + schema+"."+tableName)) {
                    pringNotFoundInfo(fountFoundInfoSet, "not found columns for fullName:"+fullName);
                    continue;
                }
                List<IntrospectedColumn> columnForSql = new ArrayList<>();
                for(String key: parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName)) {
                    IntrospectedColumn oriColumn = parameterColumns.get(key).get(0);
                    if ("sql".equals(oriColumn.getParameterCatalog())) {
                        columnForSql.add(oriColumn);
                    }
                }

                List<String> tableList = tableMapForList.get(workspaceName);
                if (CollectionUtils.isEmpty(tableList)) {
                    continue;
                }
                for(String table: tableList) {
                    if (table.equals(fullName)) {
                        table = table+"";
                    }
                }

                for(IntrospectedColumn column: columnForSql) {
                    //fix sql
                    String firstOriginalTableName = "";
                    String firstStarTableName = "";
                    Map<String, String> starTableMap = new HashMap<>();
                    Set<String> tableSet = new HashSet<>();
                    List<String> starTableKeyList = new ArrayList<>();
                    List<String> starTableKeySortedList = new ArrayList<>();

                    String parameterSql = column.getParameterSql();

                    String sqlWithoutComment = "";
                    for(String l:parameterSql.split("\n")) {
                        l = l.split("-- ")[0].trim();
                        if(l.startsWith("-- ")) {
                            continue;
                        }
                        if(!StringUtils.hasText(l)) {
                            continue;
                        }
                        sqlWithoutComment+= l + "\n";
                    }
                    String onSpaceLowerSql = parameterSql.toLowerCase().replaceAll("\n", " ")
                            .replaceAll("\t", " ")
                            .replaceAll("\r", " ")
                            .replaceAll(" select ", ",select,")
                            .replaceAll(" from ", ",from ")
                            .replaceAll("  ", " ")
                            .replaceAll(", ", ",")
                            .replaceAll(" ,", ",")
                            ;

                    if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                        Config config = SqlParser.configBuilder()
                                .setCaseSensitive(false)
                                .setQuoting(Quoting.BACK_TICK)
                                .build();

                        String sqlForPgsql = "";
                        for(String l:sqlWithoutComment.split("\n")) {
                            if("union".equals(l.toLowerCase()) || l.toLowerCase().startsWith("union ") || l.toLowerCase().startsWith("order by") || "where".equals(l.toLowerCase()) || l.toLowerCase().startsWith("where ")) {
                                try {
                                    // 解析 SQL 语句
                                    SqlParser parser = SqlParser.create(sqlForPgsql, config);
                                    SqlNode sqlNode = parser.parseQuery();
                                    break;
                                } catch (Exception e) {
                                }
                            }
                            int idx = l.toLowerCase().indexOf(" interval ");
                            if(idx > 0) {
                                while(idx > 0) {
                                    String lStr = l.substring(0, idx).trim();
                                    String rStr = l.substring(idx + " interval ".length()).trim();
                                    int cIndex = rStr.indexOf("'", 1);
                                    if(rStr.startsWith("'") && cIndex > 0) {
                                        rStr = rStr.substring(0, cIndex) + "' days " + rStr.substring(cIndex+1);
                                    }
                                    l = lStr + " interval22 "+rStr;
                                    idx = l.toLowerCase().indexOf(" interval ", idx);
                                }
                                l = l.replaceAll(" interval22 ", " interval ");
                            }
                            sqlForPgsql+= l + "\n";
                        }

                        // 创建 SQL 解析器
                        String sql = sqlForPgsql;
                        SqlParser parser = SqlParser.create(sql, config);

                        System.out.println("sql:"+column.getActualColumnName()+","+column.getParameterSql());
                        try {
                            // 解析 SQL 语句
                            SqlNode sqlNode = parser.parseQuery();
                            System.out.println("Parsed SQL: " + sqlNode.toString());
                            JSONObject j = new JSONObject();

                            parsePgsql(sqlNode, j, column);

                            if("SELECT".equals(j.getString("kind"))) {
                                String firstTable = "";
                                List<String> starTables = new ArrayList<>();
                                Map<String, String> fromTables = new HashMap<>();
                                if(j.containsKey("selectList_List_")) {
                                    JSONArray selectList_List_ = j.getJSONArray("selectList_List_");
                                    if(selectList_List_.size() > 1) { //至少 select 包括两个信息
                                        for(int i = 0; i < selectList_List_.size(); i++) {
                                            String firstS = selectList_List_.getString(i).toLowerCase().replaceAll("`", "");
                                            if(firstS.contains(".")) {
                                                if(i == 0) {
                                                    firstTable = firstS.split("\\.")[0].trim();
                                                }
                                                if(firstS.endsWith("*")) {
                                                    starTables.add(firstS.split("\\.")[0].trim());
                                                }
                                            }
                                        }
                                    }
                                }
                                parseFromTables(j, fromTables);

                                if(StringUtils.hasText(firstTable)) {
                                    if(fromTables.containsKey(firstTable)) {
                                        firstOriginalTableName = fromTables.get(firstTable);
                                    }
                                }
                                if(!CollectionUtils.isEmpty(starTables)) {
                                    firstStarTableName = starTables.get(0);
                                }
                                if(!CollectionUtils.isEmpty(fromTables)) {
                                    for(String k:fromTables.keySet()) {
                                        tableSet.add("public."+fromTables.get(k));
                                        tableSet.add("public."+k);
                                    }

                                    for(int i = 0; i < starTables.size(); i++) {
                                        String k = starTables.get(i);
                                        if(fromTables.containsKey(k)) {
                                            starTableMap.put(k, fromTables.get(k));
                                        }
                                    }
                                }
                            }

                            System.out.println("json:"+ JSONObject.toJSONString(j, SerializerFeature.PrettyFormat));
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("fixed sql:"+sql);
                            System.err.println("Error parsing SQL: " + e.getMessage());
                        }

                    }
                    if(onSpaceLowerSql.startsWith("select ")) {
                        onSpaceLowerSql = ",select,"+onSpaceLowerSql.substring("select ".length());
                    }
                    column.setParameterSimpleSql(new String(parameterSql));
                    if (StringUtils.isEmpty(parameterSql)) {
                        throw new Exception("!!! === 当parameter_catalog为sql时，parameter_sql 不能为空! "+tableName+","+column.getParameterCatalog()+"."+column.getParameterCatalogType()+", "+column.getParameterName());
                    }

                    String oriParameterSql = parameterSql;
                    String oriParameterSql2LowerCase = parameterSql.toLowerCase();

                    String extraErrorInfo = "";

                    String sql = "";

                    try {
                        List<IntrospectedColumn> introspectedColumns = new ArrayList<>();

                        PreparedStatement mysqlStatement;
                        sql = parameterSql;

                        try {
                            mysqlStatement = connection.prepareStatement(sql);
                        }catch(Exception ex) {
                            if((ex.getMessage()+"").contains("This connection has been closed")) {
                                closeConnection(workspace);
                            }
                            ex.printStackTrace(System.err);
                            System.err.println("=== prepareStatement error, sql ===");
                            System.err.println(sql);
                            throw ex;
                        }
                        ResultSetMetaData resultSetMetaData;
                        try {
                            resultSetMetaData = mysqlStatement.getMetaData();
                        }catch(Exception ex) {
                            ex.printStackTrace(System.err);
                            System.err.println("=== getMetaData error, sql ===");
                            System.err.println(sql);
                            throw new Exception(schema+"."+tableName+column.getParameterCatalog()+","+column.getParameterCatalogType()+","+column.getParameterName()+":"+ex.getMessage());
                        }

                        Object[] jdbcFields = ConnectUtil.getMetaFields(resultSetMetaData);

                        int oriColumnCount = jdbcFields.length;

                        Map<String, Method> methodMap = new HashMap<>();

                        Map<String, Field> fieldMap = new HashMap<>();

                        methodMap.put("getName", null);
                        methodMap.put("getTableName", null);
                        methodMap.put("getOriginalTableName", null);
                        methodMap.put("getOriginalColumnName", null);

                        methodMap.put("getDatabaseName", null);
                        methodMap.put("getMysqlType", null);

                        Class clz = null;
                        if (jdbcFields.length > 0) {
                            clz = jdbcFields[0].getClass();

                            checkSingleStar(sql);

                        }
                        while(clz != null) {
                            int count = 0;
                            Method[] methods = jdbcFields[0].getClass().getDeclaredMethods();
                            Field[] fields = jdbcFields[0].getClass().getDeclaredFields();
                            for(Field field: fields) {
                                try {
                                    if(!fieldMap.containsKey(field.getName()) || fieldMap.get(field.getName()) == null) {
                                        field.setAccessible(true);
                                        fieldMap.put(field.getName(), field);
                                    }
                                }catch (Exception ex) {

                                }
                            }
                            for(Method method: methods) {
                                count = 0;
                                for(String key: methodMap.keySet()) {
                                    if (methodMap.get(key) != null) {
                                        count++;
                                        continue;
                                    }
                                    String methodName = method.getName();
                                    if (key.equals(methodName)) {
                                        method.setAccessible(true);
                                        methodMap.put(key, method);
                                        count++;
                                    }
                                }
//                                if (count == methodMap.size()) {
//                                    break;
//                                }
                            }
//                            if (count == methodMap.size()) {
//                                break;
//                            }
                            clz = clz.getSuperclass();
                        }

                        List<IntrospectedColumn> oriColumns = new ArrayList<>();

                        for(Object field: jdbcFields) {

                            String fieldOriginalTableName = null;
                            Map<String, Object> fieldValueSet = new HashMap<>();
                            for(String n: fieldMap.keySet()) {
                                fieldValueSet.put(n, fieldMap.get(n).get(field));
                            }
                            if(fieldMap.get("originalTableName") != null) {
                                Object v = fieldMap.get("originalTableName").get(field);
                                if(v != null) {
                                    fieldOriginalTableName = v.toString();
                                }
                            } else if(fieldMap.get("tableOid") != null) {
                                Object v = fieldMap.get("tableOid").get(field);
                                if(v != null && tableByOidMap.containsKey(v)) {
                                    String name = tableByOidMap.get(v);
                                    fieldOriginalTableName = name.split("\\.")[1];
                                }
                            }

                            String fieldTableName = null;
                            if(fieldMap.get("tableName") != null) {
                                Object v = fieldMap.get("tableName").get(field);
                                if(v != null) {
                                    fieldTableName = v.toString();
                                }
                            }
                            String fieldName = null;
                            if(fieldMap.get("name") != null) {
                                Object v = fieldMap.get("name").get(field);
                                if(v != null) {
                                    fieldName = (String) v.toString();
                                }
                            }
                            if (fieldName == null && fieldMap.get("columnName") != null) {
                                Object v = fieldMap.get("columnName").get(field);
                                if(v != null) {
                                    fieldName = v.toString();
                                }
                            }
                            if (fieldName == null && fieldMap.get("columnLabel") != null) {
                                Object v = fieldMap.get("columnLabel").get(field);
                                if(v != null) {
                                    fieldName = v.toString();
                                }
                            }

                            String databaseName = null;
                            if(fieldMap.get("databaseName") != null) {
                                Object v = fieldMap.get("databaseName").get(field);
                                if(v != null) {
                                    databaseName = v.toString();
                                }
                            }
                            if (!StringUtils.hasText(databaseName) && "org.postgresql.Driver".equals(workspace.getDbClassname())) {
                                databaseName = "public";
                            }

                            String columnName = fieldName;
                            String columnComment = null;
                            if (fieldName.split(";").length > 1) {
                                columnName = fieldName.split(";")[0];
                                columnComment = fieldName.split(";")[1];
                            }
                            Object fieldMysqlTypeIdObject = null;
                            if(fieldMap.get("mysqlType") != null) {
                                fieldMysqlTypeIdObject = (Object) fieldMap.get("mysqlType").get(field);
                            }
                            Integer fieldMysqlTypeId;
                            if (fieldMysqlTypeIdObject instanceof Integer) {
                                fieldMysqlTypeId = (Integer) fieldMysqlTypeIdObject;
                            } else if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                                fieldMysqlTypeId = fixPostgresqlType(field, fieldMap, workspace, fieldValueSet, typeByOidMap);
                            } else {
                                fieldMysqlTypeId = ((MysqlType)fieldMysqlTypeIdObject).getJdbcType();
                            }
                            IntrospectedColumn oriColumn = new IntrospectedColumn();
                            oriColumn.setContext(context);
                            oriColumn.setActualColumnName(columnName);
                            oriColumn.setOriginalTableName(fieldOriginalTableName);
                            oriColumn.setTableName(fieldTableName);
                            oriColumn.setTypeId(fieldMysqlTypeId);
                            oriColumn.setJdbcType(fieldMysqlTypeId);
                            if (!StringUtils.isEmpty(columnComment)) {
                                oriColumn.setRemarks(columnComment);
                            }
                            oriColumns.add(oriColumn);

                            if (!StringUtils.isEmpty(fieldOriginalTableName)) {
                                if ("".equals(firstOriginalTableName)) {
                                    firstOriginalTableName = fieldOriginalTableName;
                                    if(StringUtils.hasText(fieldTableName)) {
                                        firstStarTableName = fieldTableName;
                                    }
                                }
                                tableSet.add(databaseName+"."+fieldOriginalTableName);

                                if (!starTableMap.containsKey(fieldTableName) && (
                                        parameterSql.contains(fieldTableName+".*") || parameterSql.contains("`"+fieldTableName+"`.*"))) {
                                    starTableMap.put(fieldTableName, fieldOriginalTableName);
                                }
                            }
                        }

                        Map<String, IntrospectedColumn> introspectedColumnMapForSql = new HashMap<>();

                        for(String tName: tableSet) {
                            String oriTableName = tName.split("\\.")[1];
                            String schemaname = tName.split("\\.")[0];
                            IntrospectedTable introspectedTablesForSql = introspectedTableMap.get(workspaceName + "." + schema + "." + oriTableName);
                            if (introspectedTablesForSql != null) {
                                List<IntrospectedColumn> introspectedColumnsForSql = introspectedTablesForSql.getAllColumns();

                                for (IntrospectedColumn oriIntrospectedColumn : introspectedColumnsForSql) {
                                    IntrospectedColumn introspectedColumn = new IntrospectedColumn();
                                    BeanUtils.copyProperties(oriIntrospectedColumn, introspectedColumn);

                                    String columnName;
                                    columnName = introspectedColumn.getActualColumnName();
                                    introspectedColumnMapForSql.put(schemaname + "." + oriTableName+"."+columnName, introspectedColumn);
                                }
                            }
                        }
                        for(String key: starTableMap.keySet()) {
                            starTableKeyList.add(key);
                            starTableKeySortedList.add(key);
                        }
                        Collections.sort(starTableKeySortedList,new Comparator<String>() {
                            @Override
                            public int compare(String o1, String o2) {
                                return o2.length() - o1.length();
                            }
                        });

                        mysqlStatement.close();
                        sql = "";

                        try {

                            Map<String, Integer> doneColumnNameMap = new HashMap<>();

                            //获取除xxx.*外其他的字段名称，用于处理可能存在的字段名重复问题
                            String discardStarTableSQL = column.getParameterSql();
                            int starTableIndex = 0;
                            for (String startTableName : starTableKeySortedList) {
                                discardStarTableSQL = discardStarTableSQL.replace(startTableName + ".*", "1 as discard_star_table_" + (++starTableIndex));
                                discardStarTableSQL = discardStarTableSQL.replace("`"+startTableName + "`.*", "1 as discard_star_table_" + (++starTableIndex));
                            }
                            sql = discardStarTableSQL;
                            try {
                                mysqlStatement = connection.prepareStatement(sql);
                            } catch (Exception ex) {
                                if((ex.getMessage()+"").contains("This connection has been closed")) {
                                    closeConnection(workspace);
                                }
                                ex.printStackTrace(System.err);
                                System.err.println("=== prepareStatement error, sql ===");
                                System.err.println(sql);
                                sql = column.getParameterSql();
                                mysqlStatement = connection.prepareStatement(sql);
//                                throw ex;
                            }
                            try {
                                resultSetMetaData = mysqlStatement.getMetaData();
                            } catch (Exception ex) {
                                ex.printStackTrace(System.err);
                                System.err.println("=== getMetaData error, sql ===");
                                System.err.println(sql);
                                sql = column.getParameterSql();
                                mysqlStatement = connection.prepareStatement(sql);
                                resultSetMetaData = mysqlStatement.getMetaData();
//                                throw new Exception(schema+"."+tableName+column.getParameterCatalog()+","+column.getParameterCatalogType()+","+column.getParameterName()+":"+ex.getMessage());
                            }

                            jdbcFields = ConnectUtil.getMetaFields(resultSetMetaData);

                            column.setParameterOriSql(new String(column.getParameterSql()));
                            column.setParameterSimpleWithStarSql(new String(column.getParameterSql()));

                            String validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890$_";
                            String validFirstChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
                            for (Object field : jdbcFields) {
                                String fieldName = null;
                                if(fieldMap.get("name") != null) {
                                    Object v = fieldMap.get("name").get(field);
                                    if(v != null) {
                                        fieldName = v.toString();
                                    }
                                }
                                if (fieldName == null && fieldMap.get("columnName") != null) {
                                    Object v = fieldMap.get("columnName").get(field);
                                    if(v != null) {
                                        fieldName = v.toString();
                                    }
                                }
                                if (fieldName == null && fieldMap.get("columnLabel") != null) {
                                    Object v = fieldMap.get("columnLabel").get(field);
                                    if(v != null) {
                                        fieldName = v.toString();
                                    }
                                }

                                String columnName = fieldName;
                                String columnComment = null;
                                if (SplitUtil.split(fieldName, ";").length > 1) {
                                    columnName = SplitUtil.split(fieldName, ";")[0];
                                    columnComment = SplitUtil.split(fieldName, ";")[1];
                                }
                                if (JavaReservedWords.containsWord(columnName)) {
                                    extraErrorInfo = "非法字段名（Java保留字）:" + columnName+","+ column.getParameterCatalog() + "." + column.getParameterCatalogType();
                                    throw new Exception(extraErrorInfo);
                                }
                                int cIndex = 0;
                                for (char c : columnName.toCharArray()) {
                                    if ((cIndex == 0 && validFirstChars.indexOf(c) < 0) || (cIndex > 0 && validChars.indexOf(c) < 0)) {
                                        extraErrorInfo = "非法字段名（请使用as语法对字段重命名）:" + columnName+","+column.getParameterCatalog() + "." + column.getParameterCatalogType();
                                        throw new Exception(extraErrorInfo);
                                    }
                                    cIndex++;
                                }
                                if (doneColumnNameMap.containsKey(columnName)) {
                                    extraErrorInfo = "重复的字段:" + columnName+","+column.getParameterCatalog() + "." + column.getParameterCatalogType();
                                    if(!column.getParameterSql().contains("-- ignore dup column")) {
                                        throw new Exception(extraErrorInfo);
                                    }
                                }
                                doneColumnNameMap.put(columnName, 1);
                            }

                            mysqlStatement.close();
                            sql = "";


                            if (starTableMap.size() == 0 && !StringUtils.isEmpty(firstOriginalTableName)) {
                                IntrospectedTable introspectedTablesForSql = introspectedTableMap.get(workspaceName + "." + schema + "." + firstOriginalTableName);
                                if (introspectedTablesForSql != null) {
                                    List<IntrospectedColumn> introspectedColumnsForSql = introspectedTablesForSql.getAllColumns();

                                    for (IntrospectedColumn oriIntrospectedColumn : introspectedColumnsForSql) {
                                        IntrospectedColumn introspectedColumn = new IntrospectedColumn();
                                        BeanUtils.copyProperties(oriIntrospectedColumn, introspectedColumn);

                                        String columnName;
                                        columnName = introspectedColumn.getActualColumnName();
                                        introspectedColumnMapForSql.put(columnName, introspectedColumn);
                                    }
                                }
                            }

                            Map<String, String> startTableExpandColumnsMap = new HashMap<>();

                            //处理*字段时，需要按照顺序，否则可能发生重复字段被误换名的问题，特别是在连接查询时
                            for (String startTableName : starTableKeyList) {
                                boolean needAddPrefix = false;
                                String originalTableName = starTableMap.get(startTableName);
                                if (!firstStarTableName.equals(startTableName)) {
                                    needAddPrefix = true;
                                }

                                IntrospectedTable introspectedTablesForSql = introspectedTableMap.get(workspaceName + "." + schema + "." + originalTableName);
                                if (introspectedColumnMapForSql == null) {
                                    continue;
                                }
                                if (introspectedTablesForSql == null) {
                                    System.err.println("=== not found:" + workspaceName + "." + schema + "." + originalTableName);
                                    continue;
                                }
                                List<IntrospectedColumn> oriIntrospectedColumnsForSql = introspectedTablesForSql.getAllColumns();
                                List<IntrospectedColumn> introspectedColumnsForSql = new ArrayList<>();

                                for (IntrospectedColumn oriIntrospectedColumn : oriIntrospectedColumnsForSql) {
                                    IntrospectedColumn introspectedColumn = new IntrospectedColumn();
                                    BeanUtils.copyProperties(oriIntrospectedColumn, introspectedColumn);
                                    introspectedColumnsForSql.add(introspectedColumn);
                                }

                                StringBuilder sb = new StringBuilder();
                                StringBuilder sbSub = new StringBuilder();
                                int lengthCount = 0;

                                for (IntrospectedColumn introspectedColumn : introspectedColumnsForSql) {

                                    if (sb.length() > 0) {
                                        sbSub.append(",");
                                    }
                                    String columnName = introspectedColumn.getActualColumnName().toLowerCase();

                                    if (context.autoDelimitKeywords()
                                            && SqlReservedWords.containsWord(startTableName)) {
                                        sbSub.append(escapeStringForJava(context.getBeginningDelimiter()) +
                                                startTableName + escapeStringForJava(context.getEndingDelimiter()));
                                    } else {
                                        sbSub.append(startTableName);
                                    }
                                    sbSub.append(".");

                                    if (context.autoDelimitKeywords()
                                            && SqlReservedWords.containsWord(columnName)) {
                                        sbSub.append(escapeStringForJava(context.getBeginningDelimiter()) +
                                                columnName + escapeStringForJava(context.getEndingDelimiter()));
                                    } else {
                                        sbSub.append(columnName);
                                    }

                                    sbSub.append(" as ");
                                    if (needAddPrefix) {
                                        if (!StringUtils.isEmpty(introspectedColumn.getRemarks())) {
                                            introspectedColumn.setRemarks(startTableName + " - " + introspectedColumn.getRemarks());
                                        } else {
                                            introspectedColumn.setRemarks(startTableName + " - " + columnName);
                                        }
                                        columnName = startTableName + "_" + columnName;
                                    }
                                    columnName = columnName.toLowerCase();
                                    if (doneColumnNameMap.containsKey(columnName)) {
                                        doneColumnNameMap.put(columnName, doneColumnNameMap.get(columnName) + 1);

                                        List<IntrospectedColumn> extraColumns = parameterColumns.get("sql.param."+column.getParameterCatalogType());
                                        int _loop = 0;
                                        while(true) {
                                            boolean found = false;
                                            if (extraColumns != null) {
                                                for(IntrospectedColumn c: extraColumns) {
                                                    if(StringUtils.hasText(c.getParameterSqlValue()) && c.getParameterSqlValue().equals(""+doneColumnNameMap.get(columnName))) {
                                                        doneColumnNameMap.put(columnName, doneColumnNameMap.get(columnName) + 1);
                                                        if(_loop++ > 100) {
                                                            throw new Exception(schema+"."+tableName+column.getParameterCatalog()+","+column.getParameterCatalogType()+","+column.getParameterName()+",无法重命名字段以避开sql替换值："+c.getParameterSqlValue());
                                                        }
                                                        found = true;
                                                        continue;
                                                    }
                                                }
                                            }
                                            if(!found) {
                                                break;
                                            }
                                        }
                                        columnName += doneColumnNameMap.get(columnName);
                                        introspectedColumn.setDup(true);
                                    } else {
                                        doneColumnNameMap.put(columnName, 1);
                                    }
                                    introspectedColumn.setActualColumnName(columnName);

                                    if (context.autoDelimitKeywords()
                                            && SqlReservedWords.containsWord(columnName)) {
                                        sbSub.append(escapeStringForJava(context.getBeginningDelimiter()) +
                                                columnName + escapeStringForJava(context.getEndingDelimiter()));
                                    } else {
                                        sbSub.append(columnName);
                                    }

                                    introspectedColumnMapForSql.put(columnName, introspectedColumn);
                                    introspectedColumn.setJavaProperty(JavaBeansUtil.getCamelCaseString(introspectedColumn.getActualColumnName(), false));
                                    sb.append(sbSub);
                                    sb.append("\n");
                                    sbSub.setLength(0);
                                }
                                if (sbSub.length() > 0) {
                                    sb.append(sbSub);
                                    sbSub.setLength(0);
                                }

                                startTableExpandColumnsMap.put(startTableName, sb.toString());

                                mysqlStatement.close();
                                sql = "";
                            }

                            //替换语句时需要按照表名从长到短依次替换，避免发生误替换情况。例如同时存在t.*和bat.*，如果先替换t.*就会发生错误
                            for (String startTableName : starTableKeySortedList) {
                                if(startTableExpandColumnsMap.containsKey(startTableName)) {
                                    try {
                                        column.setParameterSql(column.getParameterSql().replace(startTableName + ".*", startTableExpandColumnsMap.get(startTableName)));
                                        column.setParameterSql(column.getParameterSql().replace("`"+startTableName + "`.*", startTableExpandColumnsMap.get(startTableName)));

                                        column.setParameterSimpleSql(column.getParameterSimpleSql().replace(startTableName + ".*", startTableExpandColumnsMap.get(startTableName)));
                                        column.setParameterSimpleSql(column.getParameterSimpleSql().replace("`"+startTableName + "`.*", startTableExpandColumnsMap.get(startTableName)));
                                    }catch (Exception ex) {
                                        ex.printStackTrace();
                                        throw ex;
                                    }
                                } else {
                                    System.out.println("debugger");
                                }
                            }

                            //check if sql syntax valid
                            if (oriColumnCount > 0) {
                                sql = "select * from (\n" + column.getParameterSql() + "\n) t";
                                try {
                                    mysqlStatement = connection.prepareStatement(sql);
                                } catch (Exception ex) {
                                    if((ex.getMessage()+"").contains("This connection has been closed")) {
                                        closeConnection(workspace);
                                    }
                                    ex.printStackTrace(System.err);
                                    System.err.println("=== prepareStatement error, sql ===");
                                    System.err.println(sql);
                                    throw ex;
                                }

                                try {
                                    resultSetMetaData = mysqlStatement.getMetaData();
                                } catch (Exception ex) {
                                    ex.printStackTrace(System.err);
                                    System.err.println("=== getMetaData error, sql ===");
                                    System.err.println(sql);
                                    throw new Exception(schema+"."+tableName+column.getParameterCatalog()+","+column.getParameterCatalogType()+","+column.getParameterName()+":"+ex.getMessage());
                                }

                                mysqlStatement.close();
                            }
                            sql = "";

                        }catch(Exception ex) {
                            ex.printStackTrace(System.err);
                            System.err.println("!!! invalid sql");
                            throw ex;
                        }

                        sql = column.getParameterSql();
                        try {
                            mysqlStatement = connection.prepareStatement(sql);
                        } catch (Exception ex) {
                            if((ex.getMessage()+"").contains("This connection has been closed")) {
                                closeConnection(workspace);
                            }
                            ex.printStackTrace(System.err);
                            System.err.println("=== prepareStatement error, sql ===");
                            System.err.println(sql);
                            throw ex;
                        }

                        try {
                            resultSetMetaData = mysqlStatement.getMetaData();
                        } catch (Exception ex) {
                            ex.printStackTrace(System.err);
                            System.err.println("=== getMetaData error, sql ===");
                            System.err.println(sql);
                            throw new Exception(schema+"."+tableName+column.getParameterCatalog()+","+column.getParameterCatalogType()+","+column.getParameterName()+":"+ex.getMessage());
                        }

                        jdbcFields = ConnectUtil.getMetaFields(resultSetMetaData);

                        for (int fieldIndex = 0; fieldIndex < jdbcFields.length; fieldIndex++) {
                            Object field = jdbcFields[fieldIndex];

                            Map<String, Object> fieldValueSet = new HashMap<>();
                            for(String n: fieldMap.keySet()) {
                                fieldValueSet.put(n, fieldMap.get(n).get(field));
                            }

                            String fieldName = null;
                            if(fieldMap.get("name") != null) {
                                Object v = fieldMap.get("name").get(field);
                                if(v != null) {
                                    fieldName = v.toString();
                                }
                            }
                            if (fieldName == null && fieldMap.get("columnName") != null) {
                                Object v = fieldMap.get("columnName").get(field);
                                if(v != null) {
                                    fieldName = v.toString();
                                }
                            }
                            if (fieldName == null && fieldMap.get("columnLabel") != null) {
                                Object v = fieldMap.get("columnLabel").get(field);
                                if(v != null) {
                                    fieldName = v.toString();
                                }
                            }

                            String databaseName = null;
                            if(fieldMap.get("databaseName") != null) {
                                Object v = fieldMap.get("databaseName").get(field);
                                if(v != null) {
                                    databaseName = v.toString();
                                }
                            }
                            if (!StringUtils.hasText(databaseName) && "org.postgresql.Driver".equals(workspace.getDbClassname())) {
                                databaseName = "public";
                            }

                            String fieldOriginalTableName = null;
                            if(fieldMap.get("originalTableName") != null) {
                                Object v = fieldMap.get("originalTableName").get(field);
                                if (v != null) {
                                    fieldOriginalTableName = v.toString();
                                }
                            } else if(fieldMap.get("tableOid") != null) {
                                Object v = fieldMap.get("tableOid").get(field);
                                if(v != null && tableByOidMap.containsKey(v)) {
                                    String name = tableByOidMap.get(v);
                                    fieldOriginalTableName = name.split("\\.")[1];
                                }
                            }
                            String originalColumnName = null;
                            if(fieldMap.get("originalColumnName") != null) {
                                Object v = fieldMap.get("originalColumnName").get(field);
                                if(v != null) {
                                    originalColumnName = v.toString();
                                }
                            } else {
                                if(fieldMap.get("metadata") != null) {
                                    Object v = fieldMap.get("metadata").get(field);
                                    if(v instanceof org.postgresql.jdbc.FieldMetadata) {
                                        org.postgresql.jdbc.FieldMetadata metadata = (FieldMetadata) v;
                                        Field f = pgFieldMetadataMap.get("columnName");
                                        if(f != null) {
                                            originalColumnName = (String) f.get(v);
                                        }
                                    }
                                }
                                if(!StringUtils.hasText(originalColumnName)) {
                                    originalColumnName = fieldName;
                                }
//                                Map<String, Object> fM = new HashMap<>();
//                                for(String k: fieldMap.keySet()) {
//                                    fM.put(k, fieldMap.get(k).get(field));
//                                }
//                                fM = new HashMap<>();
                            }

                            String columnName = fieldName;
                            String columnComment = null;
                            if (fieldName.split(";").length > 1) {
                                columnName = fieldName.split(";")[0];
                                columnComment = fieldName.split(";")[1];
                            }
                            Object fieldMysqlTypeIdObject = null;
                            if(fieldMap.get("mysqlType") != null) {
                                fieldMysqlTypeIdObject = (Object) fieldMap.get("mysqlType").get(field);
                            }
                            Integer fieldMysqlTypeId;
                            if (fieldMysqlTypeIdObject instanceof Integer) {
                                fieldMysqlTypeId = (Integer) fieldMysqlTypeIdObject;
                            } else if ("org.postgresql.Driver".equals(workspace.getDbClassname())) {
                                fieldMysqlTypeId = fixPostgresqlType(field, fieldMap, workspace, fieldValueSet, typeByOidMap);
                            } else {
                                fieldMysqlTypeId = ((MysqlType) fieldMysqlTypeIdObject).getJdbcType();
                            }

                            IntrospectedColumn introspectedColumn = null;
                            IntrospectedColumn oriIntrospectedColumn = null;

                            if(introspectedColumnMapForSql.containsKey(databaseName+"."+fieldOriginalTableName+"."+columnName)) {
                                oriIntrospectedColumn = introspectedColumnMapForSql.get(databaseName+"."+fieldOriginalTableName+"."+columnName);
                            } else {
                                oriIntrospectedColumn = introspectedColumnMapForSql.get(columnName);
                            }
                            if (oriIntrospectedColumn != null){
//                                    || introspectedColumnMapForSql.containsKey(databaseName+"."+fieldOriginalTableName+"."+originalColumnName)
//                            ) {

//                                if(oriIntrospectedColumn == null) {
//                                    oriIntrospectedColumn = introspectedColumnMapForSql.get(databaseName+"."+fieldOriginalTableName+"."+originalColumnName);
//                                }
                                introspectedColumn = new IntrospectedColumn();
                                BeanUtils.copyProperties(oriIntrospectedColumn, introspectedColumn);

                                introspectedColumn.setOriginalColumnName(originalColumnName);
                                introspectedColumn.setParameterImports("");
                                introspectedColumn.setParameterJavaReturnType("");
                                introspectedColumn.setParameterJavaType(introspectedColumn.getFullyQualifiedJavaType().getFullyQualifiedName());

                                introspectedColumn.setParameterRemark(introspectedColumn.getRemarks());
                                introspectedColumn.setParameterMode("append");
                                if("sql".equals(column.getParameterCatalog())) {
                                    introspectedColumn.setParameterCatalog("api.request_for_sql");
                                } else {
                                    introspectedColumn.setParameterCatalog(column.getParameterCatalog()+"_request");
                                }
                                introspectedColumn.setSqlProjectSet(column.getSqlProjectSet());
                                introspectedColumn.setParameterCatalogType(column.getParameterCatalogType());
                                introspectedColumn.setParameterName(columnName);
                                introspectedColumn.setParameterSql("");
                                introspectedColumn.setParameterSqlValue("");

                            } else {
                                introspectedColumn = new IntrospectedColumn();
                                introspectedColumn.setOriginalColumnName(originalColumnName);
                                introspectedColumn.setContext(context);
                                introspectedColumn.setJdbcType(fieldMysqlTypeId);
                                introspectedColumn.setActualColumnName(columnName.toLowerCase());

                                IntrospectedColumn cForType = introspectedColumn;
                                if (introspectedColumnMapForSql.containsKey(databaseName + "." + fieldOriginalTableName + "." + originalColumnName)) {
                                    cForType = introspectedColumnMapForSql.get(databaseName + "." + fieldOriginalTableName + "." + originalColumnName);
                                }

                                String jdbcTypeName = javaTypeResolver
                                        .calculateJdbcTypeName(cForType);
                                if("DATETIME".equals(cForType.getSqlTypeName())) {
                                    jdbcTypeName = "TIMESTAMP";
                                }
                                String javaTypeName = resultSetMetaData.getColumnClassName(fieldIndex + 1);
                                if ("TIMESTAMP".equals(jdbcTypeName) || "java.sql.Date".equals(javaTypeName)) {
                                    javaTypeName = "java.util.Date";
                                }
                                if ("java.lang.Long".equals(javaTypeName)) {
                                    if (oriParameterSql.contains(" 0 as "+columnName.toLowerCase())
                                            || oriParameterSql.contains(" 1 as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\t0 as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\t1 as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\n0 as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\n1 as "+columnName.toLowerCase())
                                    ) {
                                        javaTypeName = "java.lang.Integer";
                                    } else if (oriParameterSql.contains(" true as "+columnName.toLowerCase())
                                            || oriParameterSql.contains(" false as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\ttrue as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\tfalse as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\ntrue as "+columnName.toLowerCase())
                                            || oriParameterSql.contains("\nfalse as "+columnName.toLowerCase())
                                    ) {
                                        javaTypeName = "java.lang.Boolean";
                                    }
                                }

                                introspectedColumn.setJdbcTypeName(jdbcTypeName);
                                introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType(javaTypeName));
                                introspectedColumn.setParameterJavaType(javaTypeName);
                                introspectedColumn.setJavaProperty(JavaBeansUtil.getCamelCaseString(columnName, false));

                                introspectedColumn.setRemarks("");
                                if(!StringUtils.hasText(introspectedColumn.getRemarks())) {
                                    if (introspectedColumnMapForSql.containsKey(databaseName + "." + fieldOriginalTableName + "." + originalColumnName)) {
                                        IntrospectedColumn c = introspectedColumnMapForSql.get(databaseName + "." + fieldOriginalTableName + "." + originalColumnName);
                                        introspectedColumn.setRemarks(c.getRemarks());
                                    }
                                }

                                introspectedColumn.setParameterImports("");
                                introspectedColumn.setParameterJavaReturnType("");

                                introspectedColumn.setParameterRemark("");
                                introspectedColumn.setParameterMode("append");
                                if("sql".equals(column.getParameterCatalog())) {
                                    introspectedColumn.setParameterCatalog("api.request_for_sql");
                                } else {
                                    introspectedColumn.setParameterCatalog(column.getParameterCatalog()+"_request");
                                }
                                introspectedColumn.setSqlProjectSet(column.getSqlProjectSet());
                                introspectedColumn.setParameterCatalogType(column.getParameterCatalogType());
                                introspectedColumn.setParameterName(columnName);
                                introspectedColumn.setParameterSql("");
                                introspectedColumn.setParameterSqlValue("");
                            }




                            if ("java.sql.Timestamp".equals(introspectedColumn.getFullyQualifiedJavaType().getFullyQualifiedName())) {
                                introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType("java.util.Date"));
                            }

                            if (!StringUtils.isEmpty(columnComment)) {
                                introspectedColumn.setParameterRemark(columnComment);
                                introspectedColumn.setRemarks(columnComment);
                            }
                            introspectedColumns.add(introspectedColumn);
                        }

                        mysqlStatement.close();
                        sql = "";

                        if("sql".equals(column.getParameterCatalog())) {

                            parameterColumns.put("api.all_columns_for_sql."+column.getParameterCatalogType(), introspectedColumns);
                            parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add("api.all_columns_for_sql."+column.getParameterCatalogType());

                            if (!parameterColumns.containsKey("api.request_for_sql."+column.getParameterCatalogType())) {
                                parameterColumns.put("api.request_for_sql."+column.getParameterCatalogType(), introspectedColumns);
                                parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add("api.request_for_sql."+column.getParameterCatalogType());
                            }
                            if (!parameterColumns.containsKey("api.response_for_sql."+column.getParameterCatalogType())) {
                                parameterColumns.put("api.response_for_sql."+column.getParameterCatalogType(), introspectedColumns);
                                parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add("api.response_for_sql."+column.getParameterCatalogType());
                            }

                            if(!Integer.valueOf(1).equals(column.getSqlIsInterface())) {
                                for(IntrospectedColumn c: introspectedColumns) {
                                    List<IntrospectedColumn> extraColumns = parameterColumns.get("sql.param."+column.getParameterCatalogType());
                                    if (extraColumns != null) {
                                        for(IntrospectedColumn c2: extraColumns) {
                                            if(!Integer.valueOf(1).equals(c2.getParameterWithoutTest())) {
                                                for(IntrospectedColumn c3: extraColumns) {
                                                    if(!Integer.valueOf(1).equals(c3.getParameterWithoutTest())) {
                                                        if(!c3.getParameterName().equals(c2.getParameterName()) && !Integer.valueOf(1).equals(c2.getParameterWithoutTest())) {
                                                            if(c2.getParameterSqlValue().contains(c3.getParameterSqlValue())
                                                                    || c3.getParameterSqlValue().contains(c2.getParameterSqlValue())) {
                                                                throw new Exception("参数值不可重叠:"+c2.getActualColumnName()+"("+c2.getParameterSqlValue()+") / " + c3.getActualColumnName()+"("+c3.getParameterSqlValue()+")");
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            if(c2.getActualColumnName().equals(c.getActualColumnName())) {
                                                if(!cn.mysdp.utils.JavaBeansUtil.isSameType(c.getFullyQualifiedJavaType().getFullyQualifiedName(), c2.getFullyQualifiedJavaType().getFullyQualifiedName())) {
                                                    if(c.getOriginalColumnName() != null) {
                                                        boolean isConst = false;
                                                        int pos = onSpaceLowerSql.indexOf(" as "+c.getActualColumnName()+",");
                                                        if(pos < 0) {
                                                            pos = onSpaceLowerSql.indexOf(" as "+c.getActualColumnName()+" ");
                                                        }
                                                        if(pos > 0) {
                                                            String _s = onSpaceLowerSql.substring(0, pos);
                                                            String[] __s = _s.split(",");
                                                            if(__s.length > 1) {
                                                                _s = __s[__s.length - 1];
                                                            }
                                                            if(_s.startsWith("'") && _s.endsWith("'")) {
                                                                isConst = true;
                                                            }
                                                            if(!isConst) {
                                                                try {
                                                                    Long l = Long.valueOf(_s);
                                                                    if(_s.equals(l+"")) {
                                                                        isConst = true;
                                                                    }
                                                                }catch (Exception ex) {

                                                                }
                                                            }
                                                            if(!isConst) {
                                                                try {
                                                                    Double l = Double.valueOf(_s);
                                                                    if(_s.equals(l+"")) {
                                                                        isConst = true;
                                                                    }
                                                                }catch (Exception ex) {

                                                                }
                                                            }

                                                        }
                                                        if(!isConst){
                                                            throw new Exception("字段类型不一致，请修改参数类型:" + c.getActualColumnName() + ",originalColumnName:" + c.getOriginalColumnName() + "(" + c.getOriginalTableName() + ")" + "," + schema + "." + tableName + column.getParameterCatalog() + "," + column.getParameterCatalogType() + "," + column.getParameterName()+",类型："+c.getFullyQualifiedJavaType().getFullyQualifiedName()+","+c2.getFullyQualifiedJavaType().getFullyQualifiedName());
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    extraColumns = parameterColumns.get("sql.response."+column.getParameterCatalogType());
                                    if (extraColumns != null) {
                                        for(IntrospectedColumn c2: extraColumns) {
                                            if(c2.getActualColumnName().equals(c.getActualColumnName())) {
                                                if("Object".equals(c2.getFullyQualifiedJavaType().getFullyQualifiedName())) {
                                                    c.setFullyQualifiedJavaType(c2.getFullyQualifiedJavaType());
                                                } else if(!cn.mysdp.utils.JavaBeansUtil.isSameType(c.getFullyQualifiedJavaType().getFullyQualifiedName(), c2.getFullyQualifiedJavaType().getFullyQualifiedName())) {
                                                    if(c.getOriginalColumnName() != null) {
                                                        boolean isConst = false;
                                                        int pos = onSpaceLowerSql.indexOf(" as "+c.getActualColumnName()+",");
                                                        if(pos < 0) {
                                                            pos = onSpaceLowerSql.indexOf(" as "+c.getActualColumnName()+" ");
                                                        }
                                                        String _lineStr = "";
                                                        if(pos > 0) {
                                                            String _s = onSpaceLowerSql.substring(0, pos);
                                                            {
                                                                int _pos = pos;
                                                                while(_pos>0) {
                                                                    _pos--;
                                                                    String _ss = onSpaceLowerSql.substring(_pos, _pos+1);
                                                                    if("\n".equals(_ss)
                                                                            || ",".equals(_ss)
                                                                            || " ".equals(_ss)
                                                                    ) {
                                                                        break;
                                                                    }
                                                                    _lineStr = _ss + _lineStr;
                                                                }
                                                            }
                                                            String[] __s = _s.split(",");
                                                            if(__s.length > 1) {
                                                                _s = __s[__s.length - 1];
                                                            }
                                                            if(_s.startsWith("'") && _s.endsWith("'")) {
                                                                isConst = true;
                                                            }
                                                            if(!isConst) {
                                                                try {
                                                                    Long l = Long.valueOf(_s);
                                                                    if(_s.equals(l+"")) {
                                                                        isConst = true;
                                                                    }
                                                                }catch (Exception ex) {

                                                                }
                                                            }
                                                            if(!isConst) {
                                                                try {
                                                                    Double l = Double.valueOf(_s);
                                                                    if(_s.equals(l+"")) {
                                                                        isConst = true;
                                                                    }
                                                                }catch (Exception ex) {

                                                                }
                                                            }

                                                        }
                                                        if(!isConst){
                                                            if(!"0".equals(_lineStr)
                                                                    && !"null".equals(_lineStr)
                                                                    && !"''".equals(_lineStr)
                                                            ) {
                                                                throw new Exception("字段类型不一致，请修改参数类型:" + c.getActualColumnName() + ",originalColumnName:"+c.getOriginalColumnName()+"("+c.getOriginalTableName()+")"+","+ schema + "." + tableName + column.getParameterCatalog() + "," + column.getParameterCatalogType() + "," + column.getParameterName()+",类型："+c.getFullyQualifiedJavaType().getFullyQualifiedName()+","+ c2.getFullyQualifiedJavaType().getFullyQualifiedName());
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        } else {
                            if (!parameterColumns.containsKey(column.getParameterCatalog()+"_request."+column.getParameterCatalogType())) {
                                parameterColumns.put(column.getParameterCatalog()+"_request."+column.getParameterCatalogType(), introspectedColumns);
                                parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add(column.getParameterCatalog()+"_request."+column.getParameterCatalogType());
                            }
                            if (!parameterColumns.containsKey(column.getParameterCatalog()+"_response."+column.getParameterCatalogType())) {
                                parameterColumns.put(column.getParameterCatalog()+"_response."+column.getParameterCatalogType(), introspectedColumns);
                                parameterColumnKeysMap.get(workspaceName + "." + schema + "." + tableName).add(column.getParameterCatalog()+"_response."+column.getParameterCatalogType());
                            }
                        }


                        List<IntrospectedColumn> extraColumns = parameterColumns.get("sql.param."+column.getParameterCatalogType());
                        if (extraColumns != null) {
                            for(IntrospectedColumn introspectedColumn: extraColumns) {
                                if (Integer.valueOf(1).equals(introspectedColumn.getParameterIgnoreSqlValue())) {
                                    continue;
                                }
                                if (StringUtils.isEmpty(introspectedColumn.getParameterJavaType())) {
                                    extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 缺少java_type属性";
                                    throw new Exception(extraErrorInfo);
                                }
                                if (StringUtils.isEmpty(introspectedColumn.getParameterSqlValue())) {
                                    extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 缺少sql_value属性";
                                    throw new Exception(extraErrorInfo);
                                }
                                String oldSql = column.getParameterSql();
                                int pos = oldSql.indexOf(introspectedColumn.getParameterSqlValue());
                                if (pos < 0) {
                                    extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 未找到参数:" + introspectedColumn.getParameterSqlValue();
                                    throw new Exception(extraErrorInfo);
                                }
                                String posPreAndAfterStr = "";
                                {
                                    int _pos = pos;
                                    try {
                                        while(_pos >= 0) {
                                            String _s = oldSql.substring(_pos, _pos+1);
                                            if(_s.equals(" ") || _s.equals("\n") || _s.equals("\t")) {
                                                break;
                                            }
                                            _pos --;
                                            posPreAndAfterStr = _s + posPreAndAfterStr;
                                        }
                                        _pos = pos + 1;
                                        int _len = oldSql.length();
                                        while(_pos <= _len - 1) {
                                            String _s = oldSql.substring(_pos, _pos+1);
                                            if(_s.equals(" ") || _s.equals("\n") || _s.equals("\t")) {
                                                break;
                                            }
                                            _pos ++;
                                            posPreAndAfterStr = posPreAndAfterStr + _s;
                                        }
                                    }catch (Exception ex) {
                                        System.err.print("posPreAndAfterStr:"+pos+","+posPreAndAfterStr);
                                        throw ex;
                                    }
                                }

                                Integer intValue = null;
                                try {
                                    intValue = Integer.valueOf(introspectedColumn.getParameterSqlValue());
                                    if (!introspectedColumn.getParameterSqlValue().equals(intValue+"")) {
                                        intValue = null;
                                    }
                                }catch(Exception ex) {
                                }
                                if (introspectedColumn.getParameterSqlValue().equals(intValue+"")) {
                                    if (pos == 0) {
                                        extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 数字不可以在语句起始处:" + introspectedColumn.getParameterSqlValue()+","+posPreAndAfterStr;
                                        throw new Exception(extraErrorInfo);
                                    }
                                    while(pos > 0) {
                                        String preChar = oldSql.substring(pos - 1, pos).toLowerCase();
                                        if(preChar.getBytes("UTF-8").length > 1) {
                                            extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 数字不可以出现在中文标识符后:" + introspectedColumn.getParameterSqlValue()+","+posPreAndAfterStr;
                                            throw new Exception(extraErrorInfo);
                                        }
                                        String validChars = "0123456789abcdefghijklmnopqrstuvwxyz_#";
                                        if (validChars.indexOf(preChar) >= 0) {
                                            extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 数字不可以出现在其他数字或标识符后:" + introspectedColumn.getParameterSqlValue()+","+posPreAndAfterStr;
                                            throw new Exception(extraErrorInfo);
                                        }
                                        pos += introspectedColumn.getParameterSqlValue().length();
                                        if (pos < oldSql.length() - 1) {
                                            String nextChar = oldSql.substring(pos, pos+1).toLowerCase();
                                            if(nextChar.getBytes("UTF-8").length > 1) {
                                                extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 数字不可以出现在中文标识符前:" + introspectedColumn.getParameterSqlValue()+","+posPreAndAfterStr;
                                                throw new Exception(extraErrorInfo);
                                            }
                                            if (validChars.indexOf(nextChar) >= 0) {
                                                extraErrorInfo = "sql.param." + column.getParameterCatalog() + "." + column.getParameterCatalogType() + "." + introspectedColumn.getParameterName() + " 数字不可以出现在其他数字或标识符前:" + introspectedColumn.getParameterSqlValue()+","+posPreAndAfterStr;
                                                throw new Exception(extraErrorInfo);
                                            }
                                        }
                                        pos = oldSql.indexOf(introspectedColumn.getParameterSqlValue(), pos);
                                    }
                                }
                                if (oldSql.indexOf("'" + introspectedColumn.getParameterSqlValue() + "'") >= 0) {
                                    extraErrorInfo = "sql.param." + introspectedColumn.getParameterName() + " 外加单引号后引起歧义";
                                    throw new Exception(extraErrorInfo);
                                }
                            }

                            int sqlIndex = 0;
                            for(String sqlStr:new String[]{column.getParameterSql(), column.getParameterSimpleSql(), column.getParameterSimpleWithStarSql()}) {
                                sqlIndex++;
                                List<String> lines = SplitUtil.splitLines(sqlStr);
                                StringBuilder sbSql = new StringBuilder();
                                for(String line: lines) {
                                    line = line.replaceAll("\r", "").replace("\n", "");
                                    String oriOriLine = line;
                                    Map<String, IntrospectedColumn> introspectedColumnFoundSet = new HashMap<>();
                                    int pos = -1;
                                    for(IntrospectedColumn introspectedColumn: extraColumns) {
                                        if (Integer.valueOf(1).equals(introspectedColumn.getParameterIgnoreSqlValue())) {
                                            continue;
                                        }
                                        pos = line.indexOf(introspectedColumn.getParameterSqlValue());
                                        if (pos >= 0) {
                                            introspectedColumnFoundSet.put(introspectedColumn.getActualColumnName(), introspectedColumn);
                                        }
                                    }

                                    if((line.trim().startsWith("-- "))) {
                                        String _line = line.trim().substring("-- ".length()).trim();
                                        if(_line.startsWith("<if")
                                                || _line.startsWith("</if")
                                                || _line.startsWith("<when")
                                                || _line.startsWith("<otherwise")
                                                || _line.startsWith("</choose")
                                                || _line.startsWith("<choose")) {
                                            if(sqlIndex == 1) {
                                                sbSql.append(line.substring("-- ".length()).split("-- ")[0]);
                                            } else {
                                                if((_line.startsWith("<if") || _line.startsWith("<when"))
                                                        && !_line.contains("simple.")) {
                                                    throw new Exception("自定义的<if或<when条件需要使用simple.作为字段前缀");
                                                }
                                                sbSql.append(line.substring("-- ".length()).split("-- ")[0].replaceAll("simple.", ""));
                                            }
                                            sbSql.append(System.lineSeparator());
                                            continue;
                                        }
                                    }
                                    if (CollectionUtils.isEmpty(introspectedColumnFoundSet)) {
                                        sbSql.append(line);
                                        sbSql.append(System.lineSeparator());
                                        continue;
                                    }
                                    for(IntrospectedColumn introspectedColumn: extraColumns) {
                                        if (Integer.valueOf(1).equals(introspectedColumn.getParameterIgnoreSqlValue())) {
                                            continue;
                                        }
                                        pos = line.indexOf(introspectedColumn.getParameterSqlValue());
                                        if (pos < 0) {
                                            continue;
                                        }
                                        if (StringUtils.hasText(introspectedColumn.getParameterSqlReplaceLine())) {
                                            line = introspectedColumn.getParameterSqlReplaceLine();
                                            if (line.endsWith("\n") || line.endsWith("\r")) {

                                            } else {
                                                line += System.lineSeparator();
                                            }
                                        } else {
                                            JSONObject extraInfo = new JSONObject();
                                            if (StringUtils.hasText(introspectedColumn.getParameterExtraInfo())) {
                                                extraInfo = JSONObject.parseObject(introspectedColumn.getParameterExtraInfo());
                                            }
                                            String paramMark = "#";
                                            if (Integer.valueOf(1).equals(extraInfo.getInteger("is_dollar"))) {
                                                paramMark = "$";
                                            }
                                            while(pos >= 0) {
                                                String newLineStr;
                                                if (Integer.valueOf(1).equals(introspectedColumn.getParameterIsCollection())) {
                                                    newLineStr = line.substring(0, pos) +
                                                            System.lineSeparator() +
                                                            "  <foreach collection=\""+
                                                            (sqlIndex == 1 ? "simple." : "") +
                                                            JavaBeansUtil.getCamelCaseString(introspectedColumn.getParameterName(), false) +
                                                            "\" item=\"data\" open=\"(\" separator=\",\" close=\")\">" +
                                                            System.lineSeparator() +
                                                            "    "+paramMark+"{data}" +
                                                            System.lineSeparator() +
                                                            "  </foreach>" +
                                                            System.lineSeparator() +
                                                            line.substring(pos +introspectedColumn.getParameterSqlValue().length());
                                                } else {
                                                    newLineStr = line.substring(0, pos) +
                                                            paramMark+"{" +
                                                            (sqlIndex == 1 ? "simple." : "") +
                                                            JavaBeansUtil.getCamelCaseString(introspectedColumn.getParameterName(), false) +
                                                            "}" +
                                                            line.substring(pos +introspectedColumn.getParameterSqlValue().length());
                                                }
                                                line = newLineStr;
                                                pos = line.indexOf(introspectedColumn.getParameterSqlValue(), pos + 20);
                                            }
                                        }
                                    }

                                    String oriLine = line;

                                    sbSql.append("]]>");
                                    sbSql.append(System.lineSeparator());

                                    for(String n: introspectedColumnFoundSet.keySet()) {
                                        IntrospectedColumn introspectedColumnFound = introspectedColumnFoundSet.get(n);

                                        if(introspectedColumnFound.getParameterNullable() == null || Integer.valueOf(1).equals(introspectedColumnFound.getParameterNullable())) {
                                            line = "<if test=\"" +
                                                    (sqlIndex == 1 ? "simple." : "") +
                                                    JavaBeansUtil.getCamelCaseString(introspectedColumnFound.getParameterName(), false) +
                                                    " != null";
                                            if (Integer.valueOf(1).equals(introspectedColumnFound.getParameterIsCollection())) {
                                                line += " and " +
                                                        (sqlIndex == 1 ? "simple." : "") +
                                                        JavaBeansUtil.getCamelCaseString(introspectedColumnFound.getParameterName(), false) +
                                                        ".size() > 0";
                                            }
                                            line += "\">";
                                            sbSql.append(line);
                                            sbSql.append(System.lineSeparator());
                                        }
                                    }

                                    String oriLineWithoutIn = oriLine.replace("<foreach collection=\"", "#1").replace("</foreach>", "#2").replace("\" item=\"data\" open=\"(\" separator=\",\" close=\")\">", "#3").replace(".size() > 0", "#4");

                                    {
                                        String _oriLine = oriLine;
                                        int commentIndex = _oriLine.indexOf("-- ");
                                        if(commentIndex == 0) {
                                            if(oriLine.contains("#{") || oriLine.contains("${")) {
                                                _oriLine = "";
                                            }
                                        } else if (commentIndex > 0) {
                                            String _comment = _oriLine.substring(commentIndex);
                                            if(_comment.contains("#{") || _comment.contains("${")) {
                                                _oriLine = _oriLine.substring(0, commentIndex);
                                            }
                                        }
                                        if ((oriLineWithoutIn.indexOf(">") >= 0 ||
                                                oriLineWithoutIn.indexOf("<") >= 0 ||
                                                oriLineWithoutIn.indexOf("&") >= 0 ||
                                                oriLineWithoutIn.indexOf("'") >= 0 ||
                                                oriLineWithoutIn.indexOf("\"") >= 0)) {
                                            line = "<![CDATA[ " +
                                                    _oriLine +
                                                    " ]]>";
                                        } else{
                                            line = _oriLine;
                                        }

                                    }
                                    sbSql.append(line);
                                    sbSql.append(System.lineSeparator());

                                    for(String n: introspectedColumnFoundSet.keySet()) {
                                        IntrospectedColumn introspectedColumnFound = introspectedColumnFoundSet.get(n);

                                        if(introspectedColumnFound.getParameterNullable() == null || Integer.valueOf(1).equals(introspectedColumnFound.getParameterNullable())) {
                                            line = "</if>" +
                                                    System.lineSeparator();
                                            sbSql.append(line);
                                        }
                                    }

                                    sbSql.append("<![CDATA[");
                                    sbSql.append(System.lineSeparator());
                                }
                                if (sqlIndex == 1) {
                                    column.setParameterSql(sbSql.toString());
                                } else if (sqlIndex == 2){
                                    column.setParameterSimpleSql(sbSql.toString());
                                } else if (sqlIndex == 3) {
                                    column.setParameterSimpleWithStarSql(sbSql.toString());
                                }

                            }
                            column.setParameterSql(fixCData(column.getParameterSql()));
                            column.setParameterSimpleSql(fixCData(column.getParameterSimpleSql()));
                            column.setParameterSimpleWithStarSql(fixCData(column.getParameterSimpleWithStarSql()));
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace(System.err);
                        System.err.println("==== 当前语句 ======================");
                        System.err.println(sql);
                        System.err.println("==== 原始语句 ======================");
                        System.err.println(oriParameterSql);
                        System.err.println("==== 附加错误 ======================");
                        System.err.println(extraErrorInfo);
                        System.err.println("==========================");
                        throw new Exception("!!! === sql错误! "+tableName+","+column.getParameterCatalog()+"."+column.getParameterCatalogType()+", "+column.getParameterName()+","+extraErrorInfo+",ex:"+ex.getMessage());
                    }

                }
            }
        }catch (Exception ex ) {
            ex.printStackTrace(System.err);
            throw ex;
        }finally {
        }

        for(String workspaceName: sdpWorkspaceMap.keySet()) {
            SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);

            if (!tableMap.containsKey(workspaceName)) {
//                pringNotFoundInfo(fountFoundInfoSet, "not found table workspace:"+workspaceName);
                continue;
            }

            List<String> tableList = tableMapForList.get(workspaceName);
            if (CollectionUtils.isEmpty(tableList)) {
                pringNotFoundInfo(fountFoundInfoSet, "not found tableList for workspace:"+workspaceName);
                continue;
            }

            for(String tableNameOri : tableList) {
                String[] names = tableNameOri.split("\\.");
                String schema = names[1];
                String tableName = names[2];
                IntrospectedTable introspectedTable = introspectedTableMap.get(workspaceName + "." + schema + "." + tableName);
                if (introspectedTable == null) {
                    for (String table : introspectedTableMap.keySet()) {
                        if (introspectedTableMap.containsKey(tableNameOri)) {
                            continue;
                        }
                        FullyQualifiedTable oriT = introspectedTableMap.get(table).getFullyQualifiedTable();

                        TableConfiguration tc = new TableConfiguration(introspectedTableMap.get(table).getContext());
                        if ("org.h2.Driver".equals(workspace.getDbClassname())) {
                            tc.setSchema("public");
                            tc.setCatalog("public");
                        } else {
                            tc.setCatalog(schema);
                        }
                        tc.setTableName(tableName);

                        FullyQualifiedTable t = new FullyQualifiedTable(
                                oriT.getIntrospectedCatalog(),
                                oriT.getIntrospectedSchema(),
                                tableName,
                                tableName,
                                tableName,
                                true,
                                null,
                                null,
                                null,
                                true,
                                null,
                                introspectedTableMap.get(table).getContext());
                        introspectedTable = ObjectFactory
                                .createIntrospectedTable(tc,
                                        t,
                                        introspectedTableMap.get(table).getContext());
                        introspectedTableMap.put(workspaceName + "." + schema + "." + tableName, introspectedTable);
                        break;
                    }
                    if (introspectedTable == null) {
                        FullyQualifiedTable t = new FullyQualifiedTable(
                                schema,
                                schema,
                                tableName,
                                tableName,
                                tableName,
                                true,
                                null,
                                null,
                                null,
                                true,
                                null,
                                contextMap.get(workspaceName));
                        introspectedTable = new IntrospectedTableMyBatis3Impl();
                        BeanUtils.copyProperties(t, introspectedTable);
                        System.err.println("==== 未找到表：" + tableName);
                        introspectedTable.setTableConfiguration(new TableConfiguration(contextMap.get(workspaceName)));
                        introspectedTable.getTableConfiguration().setCatalog(schema);
                        introspectedTable.getTableConfiguration().setTableName(tableName);
                        introspectedTable.setFullyQualifiedTable(t);
                        introspectedTableMap.put(workspaceName + "." + schema + "." + tableName, introspectedTable);
//                        continue;
                    }
                }

                try {
                    if (parameterColumnsMap.containsKey(workspaceName + "." + introspectedTable.getTableConfiguration().getCatalog() + "." + introspectedTable.getTableConfiguration().getTableName())) {
                        introspectedTable.setParameterColumns(parameterColumnsMap.get(workspaceName + "." + introspectedTable.getTableConfiguration().getCatalog() + "." + introspectedTable.getTableConfiguration().getTableName()));
                        introspectedTable.setParameterColumnKeys(parameterColumnKeysMap.get(workspaceName + "." + introspectedTable.getTableConfiguration().getCatalog() + "." + introspectedTable.getTableConfiguration().getTableName()));
                    }
                } catch (Exception ex) {
                    ex.printStackTrace(System.err);
                    throw ex;
                }
            }
        }

        Map<String, List<SdpTemplateWithBLOBs>> sdpTemplateMapByConfigId = new HashMap<>();
        Map<String, List<SdpTemplateWithBLOBs>> sdpAITemplateMapByConfigId = new HashMap<>();
        {
            SdpTemplateExample example = new SdpTemplateExample();
            if (jsonObject.containsKey("workspace_name")) {
                example.createCriteria().andWorkspaceNameEqualTo(jsonObject.getString("workspace_name"));
            }
            example.setOrderByClause("workspace_name, project_name, name");
            List<SdpTemplateWithBLOBs> sdpTemplates = sdpTemplateMapper.selectByExampleWithBLOBs(example);
            Set<String> selecteTeamplateSet = new HashSet<>();
            if(Integer.valueOf(1).equals(request.getIsAi())) {
                if(StringUtils.hasText(request.getParamInfo())) {
                    try {
                        JSONObject extraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(request.getParamInfo());
                        if(extraInfo.containsKey("selected")) {
                            JSONArray selected = extraInfo.getJSONArray("selected");
                            for(int i = 0; i < selected.size();i++) {
                                JSONObject r = selected.getJSONObject(i);
                                String k = r.getString("workspace_name")
                                        +";"+r.getString("project_name")
                                        +";"+r.getString("project")
                                        +";"+r.getString("package_name")
                                        +";"+r.getString("file_type")
                                        +";"+r.getString("name");
                                selecteTeamplateSet.add(k);
                            }
                        }
                    }catch (Exception ex) {
                        throw new Exception("param_info格式非法:"+ex.getMessage());
                    }
                }
            }
            for(SdpTemplateWithBLOBs item: sdpTemplates) {

                if(Integer.valueOf(1).equals(request.getIsAi())) {
                    if(!CollectionUtils.isEmpty(selecteTeamplateSet)) {
                        String k = item.getWorkspaceName()
                                +";"+item.getProjectName()
                                +";"+item.getProject()
                                +";"+item.getPackageName()
                                +";"+item.getFileType()
                                +";"+item.getName();
                        if(!selecteTeamplateSet.contains(k)) {
                            continue;
                        }
                    }
                    if(StringUtils.hasText(item.getExtraInfo())) {
                        try {
                            JSONObject extraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(item.getExtraInfo());
                            if(!Integer.valueOf(1).equals(extraInfo.getInteger("is_ai"))) {
                                continue;
                            }
                        }catch (Exception ex) {
                            System.err.println("project的extra_info格式非法:"+item.getWorkspaceName()+","+item.getName()+","+item.getExtraInfo());
                            System.err.println(ex.getMessage());
                            continue;
                        }
                    }
                }
                String name = item.getWorkspaceName() +";"+item.getProjectName();
                if (!sdpTemplateMapByConfigId.containsKey(name)) {
                    sdpTemplateMapByConfigId.put(name, new ArrayList<>());
                }
                sdpTemplateMapByConfigId.get(name).add(item);
            }
        }

        for(String projectNamePlus: sdpProjectMap.keySet()) {

            String workspaceName = projectNamePlus.split(";")[0];
            String projectName = projectNamePlus.split(";")[1];
            SdpProjectQueryResponse project = sdpProjectMap.get(projectNamePlus);

            if(!StringUtils.hasText(project.getTables())) {
                continue;
            }
            SdpWorkspaceQueryResponse workspace = sdpWorkspaceMap.get(workspaceName);

            String aiModel = "";
            if(Integer.valueOf(1).equals(request.getIsAi())) {
                if(StringUtils.hasText(workspace.getExtraInfo())) {
                    try {
                        JSONObject workspaceExtraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(workspace.getExtraInfo());
                        aiModel = workspaceExtraInfo.getString("model");
                    }catch (Exception ex) {
                        System.err.println("非法的workspace extra info信息："+workspace.getName()+","+workspace.getExtraInfo());
                        System.err.println(ex.getMessage());
                    }
                }
            }

            List<SdpTemplateWithBLOBs> sdpTemplate1 = sdpTemplateMapByConfigId.get(workspaceName+";"+projectName);
            if (CollectionUtils.isEmpty(sdpTemplate1)) {
                pringNotFoundInfo(fountFoundInfoSet, "not found template for project:"+workspaceName+";"+projectName);
                continue;
            }

            String schema = ConnectUtil.getDatabaseName(workspace, getConnection(workspace));
            if (StringUtils.isEmpty(project.getTables())) {
                pringNotFoundInfo(fountFoundInfoSet, "no tables for project:"+workspaceName+";"+projectName);
                continue;
            }
            String [] tables = project.getTables().split(",");
            for(String tableName: tables) {
                tableName = tableName.trim();
                String aliasName = tableName;
                String[] tableNames = tableName.split(" as ");
                if (tableNames.length > 1) {
                    tableName = tableNames[0].trim();
                    aliasName = tableNames[1].trim();
                }

                IntrospectedTable introspectedTable = introspectedTableMap.get(workspaceName + "." + schema + "." + tableName);
                if (introspectedTable == null) {
//                    if (CollectionUtils.isEmpty(introspectedTableMap)) {
                    pringNotFoundInfo(fountFoundInfoSet, "no introspectedTable for table:"+workspaceName+"."+schema+"."+tableName);
                    continue;
//                    }
                }

                for(SdpTemplateWithBLOBs item: sdpTemplate1) {
                    SdpTemplateQueryResponse dynTemplate = new SdpTemplateQueryResponse();

                    BeanUtils.copyProperties(item, dynTemplate);

                    boolean isAi = false;
                    if(StringUtils.hasText(aiModel)) {
                        if(StringUtils.hasText(item.getExtraInfo())) {
                            try {
                                JSONObject extraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(item.getExtraInfo());
                                if(Integer.valueOf(1).equals(extraInfo.getInteger("is_ai"))) {
                                    isAi = true;
                                }
                            }catch (Exception ex) {
                                System.err.println("project的extra_info格式非法:"+item.getWorkspaceName()+","+item.getName()+","+item.getExtraInfo());
                                System.err.println(ex.getMessage());
                                continue;
                            }
                        }
                    }

                    introspectedTable.setSdpTemplateMapByConfigId(sdpTemplateMapByConfigId);
                    introspectedTable.setParameterColumnsMap(parameterColumnsMap);
                    introspectedTable.setDynProjectMap(sdpProjectMap);
                    introspectedTable.setDynWorkspace(workspace);
                    introspectedTable.setDynProject(project);
                    introspectedTable.setGlobalPrepareMap(new HashMap<>());
                    introspectedTable.setAutoImportAnnotationSet(new HashSet<>());

                    if(sdpConfigMap.containsKey(workspaceName)) {
                        introspectedTable.setConfigMap(sdpConfigMap.get(workspaceName));
                        Map<String, String> configMap = introspectedTable.getConfigMap();
                        Map<String, String> autoImportAnnotationMap = new HashMap<>();
                        introspectedTable.setAutoImportAnnotationMap(autoImportAnnotationMap);
                        for(String key: configMap.keySet()) {
                            if(key.startsWith("column_annotation_auto_import_")) {
                                autoImportAnnotationMap.put(JavaBeansUtil.getCamelCaseString(key.substring("column_annotation_auto_import_".length()), true), configMap.get(key));
                            }
                        }
                    } else {
                        introspectedTable.setConfigMap(new HashMap<>());
                    }

                    dynTemplate.setAliasTableName(aliasName);

                    if (!StringUtils.isEmpty(item.getPackageName())) {
                        String content = getCompilationUnits(dataSource, introspectedTable, item.getPackageName(), dynTemplate, "", null, _processInstance, _processBodyToken, _processToken);
                        content = content.replaceAll(System.lineSeparator(), "");
                        dynTemplate.setOriPackageName(dynTemplate.getPackageName());
                        dynTemplate.setPackageName(content);
                    } else {
                        dynTemplate.setPackageName("");
                        dynTemplate.setOriPackageName("");
                    }

                    dynTemplate.setExtraInfoMap(new HashMap<>());
                    if (!StringUtils.isEmpty(item.getExtraInfo())) {
                        JSONObject extraInfo;
                        try {
                            extraInfo = JSON.parseObject(item.getExtraInfo());
                        }catch(Exception ex) {
                            System.err.println("template的extra_info非法："+item.getProjectName()+","+item.getName()+","+item.getExtraInfo());
//                            ex.printStackTrace(System.err);
                            throw new Exception("template.extra_info非法："+item.getProjectName()+","+item.getName());
                        }
                        for(String jsonKey: extraInfo.keySet()) {
                            dynTemplate.getExtraInfoMap().put(jsonKey, extraInfo.get(jsonKey));
                        }
                    }

                    if (!StringUtils.isEmpty(item.getProject())) {
                        String content = getCompilationUnits(dataSource, introspectedTable, item.getProject(), dynTemplate, "", null, _processInstance, _processBodyToken, _processToken);
                        content = content.replaceAll(System.lineSeparator(), "");
                        dynTemplate.setProject(content);
                    } else {
                        item.setProject("");
                    }

                    if (dynTemplate.getExtraInfoMap() != null) {
                        if ("1".equals(dynTemplate.getExtraInfoMap().get("has_blobs")+"")) {
                            if (!introspectedTable.hasBLOBColumns()) {
                                continue;
                            }
                        }
                        if ("0".equals(dynTemplate.getExtraInfoMap().get("has_blobs")+"")) {
                            if (introspectedTable.hasBLOBColumns()) {
                                continue;
                            }
                        }
                    }

                    File packageFile = new File(introspectedTable.getDynProject().getRootPath());
                    if (!packageFile.exists()) {
                        throw new Exception("目录不存在，请先创建目录："+introspectedTable.getDynProject().getRootPath());
                    }

                    String packageFileName = introspectedTable.getDynProject().getRootPath()+"/";
                    if (StringUtils.hasText(dynTemplate.getProject())) {
                        packageFileName += dynTemplate.getProject()+"/";
                    }
                    packageFile = new File(packageFileName);
                    if (!packageFile.exists()) {
                        try {
                            System.out.println("mkdirs:"+packageFile.getAbsolutePath());
                            packageFile.mkdirs();
                            if(packageFile.getAbsolutePath().endsWith("/null")) {
                                System.err.println("!!!mkdirs last path is null");
                            }

                        }catch (Exception ex) {
                            ex.printStackTrace(System.err);
                            throw new Exception("目录不存在，且无法创建："+packageFileName);
                        }
                    }
                    if (!packageFile.isDirectory()) {
                        throw new Exception("目标不是目录："+packageFileName);
                    }

                    introspectedTable.setSdpTemplateMapByConfigId(sdpTemplateMapByConfigId);
                    introspectedTable.setParameterColumnsMap(parameterColumnsMap);
                    introspectedTable.setDynProjectMap(sdpProjectMap);
                    introspectedTable.setDynWorkspace(workspace);
                    introspectedTable.setDynProject(project);
                    introspectedTable.setGlobalPrepareMap(new HashMap<>());
                    introspectedTable.setAutoImportAnnotationSet(new HashSet<>());

                    if(sdpConfigMap.containsKey(workspaceName)) {
                        introspectedTable.setConfigMap(sdpConfigMap.get(workspaceName));
                        Map<String, String> configMap = introspectedTable.getConfigMap();
                        Map<String, String> autoImportAnnotationMap = new HashMap<>();
                        introspectedTable.setAutoImportAnnotationMap(autoImportAnnotationMap);
                        for(String key: configMap.keySet()) {
                            if(key.startsWith("column_annotation_auto_import_")) {
                                autoImportAnnotationMap.put(JavaBeansUtil.getCamelCaseString(key.substring("column_annotation_auto_import_".length()), true), configMap.get(key));
                            }
                        }
                    } else {
                        introspectedTable.setConfigMap(new HashMap<>());
                    }

                    if (dynTemplate.getName().indexOf("{sql_name") >= 0) {
                        for(String key: introspectedTable.getParameterColumnKeys()) {
                            if (key.startsWith("api.request_for_sql.")) {
                                String sqlMethodName = key.replace("api.request_for_sql.", "");

                                if (!CollectionUtils.isEmpty(dynTemplate.getExtraInfoMap())) {
                                    List<IntrospectedColumn> columns = introspectedTable.getParameterColumns().get("sql."+sqlMethodName);
                                    if (CollectionUtils.isEmpty(columns)) {
                                        System.err.println("miss sql."+key);
                                        continue;
                                    }
                                    if (!CollectionUtils.isEmpty(columns)) {
                                        IntrospectedColumn column = columns.get(0);
                                        if ("sql".equals(column.getParameterCatalog())) {
                                            if ("0".equals(dynTemplate.getExtraInfoMap().get("is_interface")+"")) {
                                                if (Integer.valueOf(1).equals(column.getSqlIsInterface())) {
                                                    continue;
                                                }
                                            }
                                        }
                                    }
                                }
                                Map<String, List<String>> oldGlobalPrepareMap = introspectedTable.getGlobalPrepareMap();
                                introspectedTable.setGlobalPrepareMap(new HashMap<>());
                                String fileName = getCompilationUnits(dataSource, introspectedTable, dynTemplate.getName(), dynTemplate, "", sqlMethodName, _processInstance, _processBodyToken, _processToken);
                                if(!StringUtils.hasText(fileName)) {
                                    System.out.println("ignore:"+ introspectedTable.getDynProject().getRootPath()+";"+ dynTemplate.getOriPackageName()+";"+ dynTemplate.getPackageName()+";"+sqlMethodName+";"+introspectedTable.getFullyQualifiedTable().getIntrospectedTableName());
                                    continue;
                                }
                                introspectedTable.setGlobalPrepareMap(oldGlobalPrepareMap);
                                fileName = fileName.replaceAll(System.lineSeparator(), "");

                                System.out.println("process:"+ introspectedTable.getDynProject().getRootPath()+";"+ dynTemplate.getProject()+";"+ dynTemplate.getPackageName()+";"+fileName+";"+introspectedTable.getFullyQualifiedTable().getIntrospectedTableName());

                                String fullFileName = introspectedTable.getDynProject().getRootPath();
                                if(StringUtils.hasText(dynTemplate.getProject())) {
                                    fullFileName += "/"+ dynTemplate.getProject()+"/";
                                }
                                if(StringUtils.hasText(dynTemplate.getOriPackageName()) && dynTemplate.getOriPackageName().indexOf("project_root_path_tail") >= 0) {
                                } else {
                                    fullFileName += "/"+ dynTemplate.getPackageName().replaceAll("\\.", "/");
                                }
                                fullFileName += "/"+fileName+"."+ dynTemplate.getFileType();
                                File file = new File(fullFileName);

                                if (Integer.valueOf(1).equals(dynTemplate.getNoOverwrite())) {
                                    if (file.exists()) {
                                        continue;
                                    }
                                }

                                FileUtil.fetchFileOldProperty(file);

                                String content = getCompilationUnits_for_wirte_file(introspectedTable, dynTemplate.getFileTemplate(), dynTemplate, fileName, sqlMethodName, _processInstance, _processBodyToken, _processToken);

                                if(StringUtils.hasText(aiModel) && isAi) {
                                    content = processAiContent(content, workspace, dynTemplate, fileName);
                                }
                                writeFile(file, content);
                            }
                        }
                    } else {
                        String fileName = getCompilationUnits(dataSource, introspectedTable, dynTemplate.getName(), dynTemplate, "", null, _processInstance, _processBodyToken, _processToken);
                        if(!StringUtils.hasText(fileName)) {
                            System.out.println("ignore:"+ introspectedTable.getDynProject().getRootPath()+";"+ dynTemplate.getOriPackageName()+";"+ dynTemplate.getPackageName()+";"+introspectedTable.getFullyQualifiedTable().getIntrospectedTableName());
                            continue;
                        }
                        fileName = fileName.replaceAll(System.lineSeparator(), "");
                        System.out.println("process:"+ introspectedTable.getDynProject().getRootPath()+";"+ dynTemplate.getProject()+";"+ dynTemplate.getPackageName()+";"+fileName+";"+introspectedTable.getFullyQualifiedTable().getIntrospectedTableName());

                        String fullFileName;
                        fullFileName = introspectedTable.getDynProject().getRootPath();
                        if(StringUtils.hasText(dynTemplate.getProject())) {
                            fullFileName += "/"+ dynTemplate.getProject();
                        }
                        if(StringUtils.hasText(dynTemplate.getOriPackageName()) && dynTemplate.getOriPackageName().indexOf("project_root_path_tail") >= 0) {
                        } else {
                            fullFileName += "/"+ dynTemplate.getPackageName().replaceAll("\\.", "/");
                        }
                        fullFileName += "/"+fileName+"."+ dynTemplate.getFileType();
                        File file = new File(fullFileName);

                        if (Integer.valueOf(1).equals(dynTemplate.getNoOverwrite())) {
                            if (file.exists()) {
                                continue;
                            }
                        }

                        FileUtil.fetchFileOldProperty(file);

                        String template = dynTemplate.getFileTemplate();
                        if(template.indexOf("{template&") >= 0) {
                            int pos = template.indexOf("{template&");
                            String newTemplate = template.substring(0, pos);
                            String str = template.substring(pos+1);
                            byte[] srcBytes = str.getBytes("UTF-8");
                            pos = 0;
                            int level = 1;
                            int len = srcBytes.length;
                            byte[] destBytes = new byte[len];
                            while(pos < len) {
                                byte srcByte = srcBytes[pos];
                                destBytes[pos] = srcByte;
                                pos++;
                                if(srcByte== '{') {
                                    level++;
                                } else if(srcByte == '}') {
                                    level--;
                                    if(level == 0) {
                                        break;
                                    }
                                }
                            }
                            if(level != 0) {
                                throw new Exception("template分析失败：缺少必要的}");
                            }
                            String destStr = new String(destBytes, "UTF-8").trim();
                            if(destStr.endsWith("}")) {
                                destStr = destStr.substring(0, destStr.length() - 1);
                            }
                            String _projectName = null;
                            String _templateName = dynTemplate.getName();
                            if(destStr.indexOf("&project_name=") >= 0) {
                                _projectName = destStr.split("&project_name=")[1].split("&")[0].trim();
                            } else {
                                throw new Exception("miss project_name in template!");
                            }
                            if(destStr.indexOf("&name=") >= 0) {
                                _templateName = destStr.split("&name=")[1].split("&")[0].trim();
                            }
                            SdpTemplateWithBLOBs srcTemplateRecord = null;
                            for(List<SdpTemplateWithBLOBs> ts: introspectedTable.getSdpTemplateMapByConfigId().values()) {
                                for(SdpTemplateWithBLOBs t: ts) {
                                    if(_projectName.equals(t.getProjectName()) && _templateName.equals(t.getName())) {
                                        srcTemplateRecord = t;
                                        break;
                                    }
                                }
                            }
                            if(srcTemplateRecord == null) {
                                throw new Exception("无法找到对应模板："+dynTemplate.getWorkspaceName()+","+_projectName+","+_templateName);
                            }
                            newTemplate += srcTemplateRecord.getFileTemplate();
                            if(pos < len) {
                                byte[]destBytes2 = new byte[len - pos];
                                System.arraycopy(srcBytes, pos, destBytes2, 0, len - pos);
                                String destStr2 = new String(destBytes2, "UTF-8");
                                newTemplate += destStr2;
                            }
                            template = newTemplate;

                        }
                        introspectedTable.setIntrospectedTableMap(introspectedTableMap);

                        String content = getCompilationUnits_for_wirte_file(introspectedTable, template, dynTemplate, fileName, null, _processInstance, _processBodyToken, _processToken);

                        if(StringUtils.hasText(aiModel) && isAi) {
                            content = processAiContent(content, workspace, dynTemplate, fileName);
                        }
                        writeFile(file, content);
                    }
                }
            }
        }

        SdpProjectForExecuteResponse result = new SdpProjectForExecuteResponse();
        return result;
    }

    private String processAiContent_localOllama(String content, String aiModel, SdpTemplateQueryResponse dynTemplate, String fileName) throws Exception {
        System.out.println("processAiContent_localOllama fileName:"+fileName);
        System.out.println("fielType:"+dynTemplate.getFileType());
        String str = FileUtil.callCmdWithStdin("ollama\nrun\n"+aiModel, content);
        String[]strs = str.split("```"+dynTemplate.getFileType());
        System.out.println("strs.length:"+strs.length);
        String contentStr = "";
        String saleFileTypeContentStr = "";
        int count = 0;
        for(int i = 0; i < strs.length;i++) {
            String s = strs[i];
            if(s.contains("```")) {
                s = s.split("```")[0].trim();
                if(StringUtils.hasText(s)) {
                    if(s.length() > contentStr.length()) {
                        contentStr = s;
                    }
                    count++;
                }
                if("java".equals(dynTemplate.getFileType())) {
                    if(s.contains("class "+fileName) || s.contains("interface "+fileName)) {
                        saleFileTypeContentStr = s;
                    }
                }
            }
        }
        if(count == 1) {
            System.out.println("===== count=1 content =====");
            System.out.println(content);
            content = contentStr;
        } if(StringUtils.hasText(saleFileTypeContentStr)) {
            System.out.println("===== saleFileTypeContentStr content =====");
            System.out.println(content);
            content = saleFileTypeContentStr;
        } else {
            content = content + "\n\n/*\n"+str+"\n*/";
        }
        return content;
    }
    private String processAiContent(String content, SdpWorkspaceQueryResponse workspace, SdpTemplateQueryResponse dynTemplate, String fileName) throws Exception {
        String aiModel = "";
        Boolean isLocalOllama = false;
        if(StringUtils.hasText(workspace.getExtraInfo())) {
            try {
                JSONObject workspaceExtraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(workspace.getExtraInfo());
                aiModel = workspaceExtraInfo.getString("model");
                if(Integer.valueOf(1).equals(workspaceExtraInfo.getInteger("is_local_ollama"))) {
                    isLocalOllama = true;
                }
            }catch (Exception ex) {
                System.err.println("非法的workspace extra info信息："+workspace.getName()+","+workspace.getExtraInfo());
                System.err.println(ex.getMessage());
            }
        }

        if(!StringUtils.hasText(aiModel)) {
            return content;
        }

        boolean isAi = false;
        if(StringUtils.hasText(aiModel)) {
            if(StringUtils.hasText(dynTemplate.getExtraInfo())) {
                try {
                    JSONObject extraInfo = cn.mysdp.utils.JavaBeansUtil.parseObject(dynTemplate.getExtraInfo());
                    if(Integer.valueOf(1).equals(extraInfo.getInteger("is_ai"))) {
                        isAi = true;
                    }
                }catch (Exception ex) {
                    System.err.println("project的extra_info格式非法:"+dynTemplate.getWorkspaceName()+","+dynTemplate.getName()+","+dynTemplate.getExtraInfo());
                    System.err.println(ex.getMessage());
                    return content;
                }
            }
        }
        if(!isAi) {
            return content;
        }

        if(isLocalOllama) {
            content = processAiContent_localOllama(content, aiModel, dynTemplate, fileName);
        }
        return content;
    }

    private void writeFile(File file, String content) throws Exception {
        FileOutputStream fos = null;
        BufferedWriter writer = null;
        try {
            System.out.println("mkdirs:"+file.getParentFile().getAbsolutePath());
            if(file.getParentFile().getAbsolutePath().endsWith("/null")) {
                System.err.println("!!!mkdirs last path is null");
            }
            file.getParentFile().mkdirs();
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
            throw ex;
        }
        try {
            fos = new FileOutputStream(file);

            System.err.println("write file:"+file.getAbsolutePath());

            writer = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));

            writer.write(content);
            writer.close();
            writer = null;
            fos.close();
            fos = null;

        } catch (Exception ex) {
            ex.printStackTrace(System.err);
            throw ex;
        }finally {
            if (writer != null) {
                writer.close();
            }
            if (fos != null) {
                fos.close();
            }
        }
    }

    ProcessUtil processUtil = new ProcessUtil();

    public DynProcessTokenResult processToken(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, List<IntrospectedColumn> columns, Integer columnIndex, String token, JSONObject properties, Object _processInstance, Method _processBodyToken, Method _processToken, ByteWithPos prefixBytes) throws Exception {
        return processUtil.processToken(dataSource, introspectedTable, dynTemplate, fileName, sqlMethodName, columns, columnIndex,
                token, properties, _processInstance, _processBodyToken, _processToken, prefixBytes);
    }

    private String getCompilationUnits_for_wirte_file(IntrospectedTable introspectedTable, String template, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {
        introspectedTable.setHasAutoImportAnnotation(false);
        String result = getCompilationUnits(dataSource, introspectedTable, template, dynTemplate, fileName, sqlMethodName, _processInstance, _processBodyToken, _processToken);
        String[] globalPrepares = result.split("\\{global_prepare&");

        Map<String, Map<String, String>> globalPrepareMap = new HashMap<>();
        for(int i = 1; i < globalPrepares.length; i++) {
            String command = globalPrepares[i].split("}")[0];
            String[] _ss1 = command.split("&");
            String name = null;
            for(String _s2: _ss1) {
                if(_s2.indexOf("=") > 0) {
                    String _l = _s2.substring(0, _s2.indexOf("=")).trim();
                    String _r = _s2.substring(_s2.indexOf("=")+1);
                    if("name".equals(_l)) {
                        name = _r.trim();
                        if(StringUtils.hasText(name)) {
                            if(!globalPrepareMap.containsKey(name)) {
                                globalPrepareMap.put(name, new HashMap<>());
                                globalPrepareMap.get(name).put("_command", "{global_prepare&"+command+"}");
                            }
                        }
                    }
                }
            }
            if(StringUtils.hasText(name)) {
                for(String _s2: _ss1) {
                    if(_s2.indexOf("=") > 0) {
                        String _l = _s2.substring(0, _s2.indexOf("=")).trim();
                        String _r = _s2.substring(0, _s2.indexOf("=")+1);
                        if(!"name".equals(_l)) {
                            globalPrepareMap.get(name).put(_l, _r);
                        }
                    }
                }
            }
        }

        if(!CollectionUtils.isEmpty(globalPrepareMap)) {
            for(String name:globalPrepareMap.keySet()) {
                List<String> _ss = introspectedTable.getGlobalPrepareMap().get(name);
                String destStr = "";
                if(!CollectionUtils.isEmpty(_ss))  {
                    for(String _s:_ss) {
                        if(StringUtils.hasText(destStr)) {
                            destStr += System.lineSeparator();
                        }
                        destStr += _s;
                    }
                }
                String _command = globalPrepareMap.get(name).get("_command");
                if(StringUtils.hasText(_command)) {
                    int pos = result.indexOf(globalPrepareMap.get(name).get("_command"));
                    String newResult = "";
                    if(pos > 0) {
                        newResult += result.substring(0, pos);
                    }
                    newResult += destStr;
                    newResult += result.substring(pos + globalPrepareMap.get(name).get("_command").length());
                    result = newResult;
                }
            }
        }
        if(introspectedTable.isHasAutoImportAnnotation()) {
            if(!CollectionUtils.isEmpty(introspectedTable.getConfigMap())) {
                Map<String, String> configMap = introspectedTable.getConfigMap();
                Map<String, String> autoImportAnnotationMap = new HashMap<>();
                for(String key: configMap.keySet()) {
                    if(key.startsWith("column_annotation_auto_import_")) {
                        autoImportAnnotationMap.put(JavaBeansUtil.getCamelCaseString(key.substring("column_annotation_auto_import_".length()), true), configMap.get(key));
                    }
                }
                String destStr = "";
                for(String key: introspectedTable.getAutoImportAnnotationSet()) {
                    if (autoImportAnnotationMap.containsKey(key)) {
                        if(StringUtils.hasText(destStr)) {
                            destStr += System.lineSeparator();
                        }
                        destStr += autoImportAnnotationMap.get(key);
                    }
                }
                int pos = result.indexOf("{auto_import_annotation}");
                if(pos >= 0) {
                    String newResult = "";
                    if(pos > 0) {
                        newResult = result.substring(0, pos);
                    }
                    newResult += destStr;
                    newResult += result.substring(pos+"{auto_import_annotation}".length());
                    result = newResult;
                } else {
                    throw new Exception("自动导入java包仅支持：{auto_import_annotation}格式");
                }
            }
        }
        return result;
    }

    private String getCompilationUnits(DataSource dataSource, IntrospectedTable introspectedTable, String template, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {

        return processUtil.getCompilationUnits(dataSource, introspectedTable, template, dynTemplate, fileName, sqlMethodName, _processInstance, _processBodyToken, _processToken);

    }
    public DynProcessTokenResult processBodyToken(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, List<ByteWithPos> lineBytesList, List<String> lineStringList, List<String> lineTrimStringList, List<Integer> deepList, int deep, ByteWithPos destBytes, String vTrim, List<IntrospectedColumn> inColumns, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {
        return processUtil.processBodyToken(dataSource, introspectedTable, dynTemplate, fileName, sqlMethodName, lineBytesList,
                lineStringList, lineTrimStringList, deepList, deep, destBytes, vTrim, inColumns, _processInstance, _processBodyToken, _processToken);
    }

    @Override
    public DynProcessTokenResult processBodyTokenProperties(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, List<ByteWithPos> lineBytesList, List<String> lineStringList, List<String> lineTrimStringList, List<Integer> deepList, int deep, ByteWithPos destBytes, String vTrim, JSONObject properties, List<IntrospectedColumn> inColumns) throws Exception {
        return processUtil.processBodyTokenProperties(dataSource, introspectedTable, dynTemplate, fileName, sqlMethodName, lineBytesList, lineStringList,lineTrimStringList, deepList,deep, destBytes, vTrim, properties, inColumns);
    }

    @Override
    public void processBodyTokenWithColumns(DataSource dataSource, IntrospectedTable introspectedTable, SdpTemplateQueryResponse dynTemplate, String fileName, String sqlMethodName, List<ByteWithPos> lineBytesList, List<String> lineStringList, List<String> lineTrimStringList, List<Integer> deepList, int deep, ByteWithPos destBytes, String vTrim, JSONObject properties, List<IntrospectedColumn> inColumns, List<IntrospectedColumn> introspectedColumns, List<IntrospectedColumn> extraColumns, Object _processInstance, Method _processBodyToken, Method _processToken) throws Exception {
        processUtil.processBodyTokenWithColumns(dataSource, introspectedTable,dynTemplate,fileName,sqlMethodName,lineBytesList,lineStringList,lineTrimStringList,deepList,deep,destBytes,vTrim,properties,inColumns,introspectedColumns,extraColumns,_processInstance,_processBodyToken,_processToken);

    }

    String fixCData(String oldSql) {
        int pos = 0;
        String startStr = System.lineSeparator()+"<![CDATA[";
        String endStr = System.lineSeparator()+"]]>";
        do {
            pos = oldSql.indexOf(startStr, pos);
            if (pos < 0) {
                break;
            }
            int endPos = oldSql.indexOf(endStr, pos);
            if (endPos < 0) {
                break;
            }
            String midStr = oldSql.substring(pos, endPos+endStr.length());
            midStr = midStr.replaceAll(System.lineSeparator(), "");
            if ("<![CDATA[]]>".equals(midStr)) {
                oldSql = oldSql.substring(0, pos) + oldSql.substring(endPos + endStr.length());
            } else {
                pos += 10;
            }
        }while (pos >= 0);
        return oldSql;
    }

    @Getter
    @Setter
    public static class H2MetaField {
        public String name;
        public String tableName;
        public String originalTableName;
        public Integer mysqlType;

        public void setMysqlType(int type) {
            mysqlType = type;
        }
    }

    void parseFromTables(JSONObject j, Map<String, String> fromTables) {
        try {
            if(j.containsKey("from")) {
                parseFromTables(j.getJSONObject("from"), fromTables);
                return;
            }
            if("AS".equals(j.getString("kind")) && j.containsKey("operandList_List_") && j.getJSONArray("operandList_List_").size() == 2) {
                JSONArray l = j.getJSONArray("operandList_List_");
                fromTables.put(l.getString(1).toLowerCase().replaceAll("`", ""), l.getString(0).toLowerCase().replaceAll("`", ""));
            }
            if(j.containsKey("left")) {
                parseFromTables(j.getJSONObject("left"), fromTables);
            }
            if(j.containsKey("right")) {
                parseFromTables(j.getJSONObject("right"), fromTables);
            }
        }catch (Exception ex) {

        }
    }

    void parsePgsql(SqlNode sqlNode, JSONObject j, IntrospectedColumn column) {
        parsePgsql(sqlNode, j, column, new HashSet<>());
    }
    void parsePgsql(SqlNode sqlNode, JSONObject j, IntrospectedColumn column, Set<Object> doneNodeSet) {
        if(doneNodeSet == null) {
            doneNodeSet = new HashSet<>();
        }
        if(doneNodeSet.contains(sqlNode)) {
            return;
        }
        doneNodeSet.add(sqlNode);
        try {
            j.put("kind", sqlNode.getKind());
            if(sqlNode instanceof SqlOrderBy) {
                parsePgsql(((SqlOrderBy)sqlNode).query, j, column, doneNodeSet);
                return;
            }
            Class clz = sqlNode.getClass();
            while(clz != null) {
                Field[] fs = clz.getDeclaredFields();
                for(Field f: fs) {
                    if("where".equals(f.getName())
                            || "parserPosition".equals(f.getName())
                            || "joinType".equals(f.getName())
                            || "conditionType".equals(f.getName())
                            || "windowDecls".equals(f.getName())
                            || "condition".equals(f.getName())
                            || "natural".equals(f.getName())
                            || "operator".equals(f.getName())
                            || "COMMA_OPERATOR".equals(f.getName())
//                            || "OPERATOR".equals(f.getName())
                            || "HAVING_OPERAND".equals(f.getName())
                            || "FROM_OPERAND".equals(f.getName())
                            || "keywordList".equals(f.getName())
                            || "pos".equals(f.getName())
                            || "QUALIFY_OPERAND".equals(f.getName())
                            || "groupBy".equals(f.getName())
                            || "EMPTY_ARRAY".equals(f.getName())
                            || "hints".equals(f.getName())
                    ) {
                        j.put(f.getName(), "ignore");
                        continue;
                    }
                    Object o = null;
                    try {
                        f.setAccessible(true);
                        o = f.get(sqlNode);
                        if(o == null) {
                            continue;
                        }
                        if (!(o instanceof List) && o.getClass().isArray()) {
                            int length = java.lang.reflect.Array.getLength(o);
                            if(length > 0) {
                                List<Object> _o = new ArrayList<>();
                                for (int i = 0; i < length; i++) {
                                    Object element = java.lang.reflect.Array.get(o, i);
                                    _o.add(element);
                                }
                                o = _o;
                            }
                        }
                        if(o instanceof List &&( (List) o).size() > 0) {
                            List o2 = (List)o;
                            List<Object> a = new ArrayList<>();
                            List<Object> b = new ArrayList<>();
                            List<Object> c = new ArrayList<>();
                            List<Object> e = new ArrayList<>();
                            boolean hasException = false;
                            for(int i = 0; i < o2.size(); i++) {
                                c.add(o2.get(i).getClass().getName());
                                a.add(o2.get(i)+"");
                                if(o2.get(i) instanceof SqlNode) {
                                    JSONObject _j2 = new JSONObject();
                                    b.add(_j2);
                                    parsePgsql((SqlNode) o2.get(i), _j2, column, doneNodeSet);
                                    e.add("");
                                } else {
                                    try {
                                        String sT = JSONObject.toJSONString(o2.get(i));
                                        b.add(o2.get(i));
                                        e.add("");
                                    }catch (Exception ex2) {
                                        hasException = true;
                                        b.add(o2.get(i)+"");
                                        e.add(ex2.getMessage());
                                    }
                                }
                            }

                            if(hasException) {
                                j.put(f.getName()+"_Clz_", c);
                                j.put(f.getName()+"_Ex_", e);
                            }
                            j.put(f.getName()+"_List_", a);
                            j.put(f.getName(), b);
                            continue;
                        }

                        if(o instanceof SqlNode && (
                                "left".equals(f.getName())
                                        || "right".equals(f.getName())
                        )) {
                            JSONObject jO = new JSONObject();
                            j.put(f.getName(), jO);
                            parsePgsql((SqlNode) o, jO, column, doneNodeSet);
                        } else {
                            try {
                                String tS = JSONObject.toJSONString(o);
                                j.put(f.getName(), o);
                            }catch (Exception ex) {
                                j.put(f.getName()+"_Ex_", ex.getMessage());
                                if(o instanceof SqlNode) {
                                    JSONObject jO = new JSONObject();
                                    j.put(f.getName(), jO);
                                    parsePgsql((SqlNode) o, jO, column, doneNodeSet);
                                } else {
                                    j.put(f.getName(), o+"");
                                }
                            }
                        }
                    }catch (Exception ex) {
                        if(o != null) {
                            j.put(f.getName()+"_Clz_", o.getClass().getName());
                        }
                        j.put(f.getName()+"_Ex_", ex.getMessage());
                        j.put(f.getName(), o+"");
                    }
                }
                clz = clz.getSuperclass();
            }
        } catch (Exception e) {
            j.put("_clz_", sqlNode.getClass().getName());
            j.put("_kind_", sqlNode.getKind());
            j.put("_pos_", sqlNode.getParserPosition());
            j.put("_ex_", e.getMessage());
        }
    }

}
